Merge branch 'lp/config-vername-check'
* lp/config-vername-check: Disallow empty section and variable names Sanity-check config variable names
This commit is contained in:
commit
fbfeeaf294
@ -153,7 +153,6 @@ static int show_config(const char *key_, const char *value_, void *cb)
|
|||||||
static int get_value(const char *key_, const char *regex_)
|
static int get_value(const char *key_, const char *regex_)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
char *tl;
|
|
||||||
char *global = NULL, *repo_config = NULL;
|
char *global = NULL, *repo_config = NULL;
|
||||||
const char *system_wide = NULL, *local;
|
const char *system_wide = NULL, *local;
|
||||||
|
|
||||||
@ -167,18 +166,32 @@ static int get_value(const char *key_, const char *regex_)
|
|||||||
system_wide = git_etc_gitconfig();
|
system_wide = git_etc_gitconfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_key_regexp) {
|
||||||
|
char *tl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NEEDSWORK: this naive pattern lowercasing obviously does not
|
||||||
|
* work for more complex patterns like "^[^.]*Foo.*bar".
|
||||||
|
* Perhaps we should deprecate this altogether someday.
|
||||||
|
*/
|
||||||
|
|
||||||
key = xstrdup(key_);
|
key = xstrdup(key_);
|
||||||
for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
|
for (tl = key + strlen(key) - 1;
|
||||||
|
tl >= key && *tl != '.';
|
||||||
|
tl--)
|
||||||
*tl = tolower(*tl);
|
*tl = tolower(*tl);
|
||||||
for (tl=key; *tl && *tl != '.'; ++tl)
|
for (tl = key; *tl && *tl != '.'; tl++)
|
||||||
*tl = tolower(*tl);
|
*tl = tolower(*tl);
|
||||||
|
|
||||||
if (use_key_regexp) {
|
|
||||||
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
|
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
|
||||||
if (regcomp(key_regexp, key, REG_EXTENDED)) {
|
if (regcomp(key_regexp, key, REG_EXTENDED)) {
|
||||||
fprintf(stderr, "Invalid key pattern: %s\n", key_);
|
fprintf(stderr, "Invalid key pattern: %s\n", key_);
|
||||||
|
free(key);
|
||||||
goto free_strings;
|
goto free_strings;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (git_config_parse_key(key_, &key, NULL))
|
||||||
|
goto free_strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regex_) {
|
if (regex_) {
|
||||||
|
1
cache.h
1
cache.h
@ -1014,6 +1014,7 @@ extern int git_config_maybe_bool(const char *, const char *);
|
|||||||
extern int git_config_string(const char **, const char *, const char *);
|
extern int git_config_string(const char **, const char *, const char *);
|
||||||
extern int git_config_pathname(const char **, const char *, const char *);
|
extern int git_config_pathname(const char **, const char *, const char *);
|
||||||
extern int git_config_set(const char *, const char *);
|
extern int git_config_set(const char *, const char *);
|
||||||
|
extern int git_config_parse_key(const char *, char **, int *);
|
||||||
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
||||||
extern int git_config_rename_section(const char *, const char *);
|
extern int git_config_rename_section(const char *, const char *);
|
||||||
extern const char *git_etc_gitconfig(void);
|
extern const char *git_etc_gitconfig(void);
|
||||||
|
111
config.c
111
config.c
@ -1098,6 +1098,75 @@ int git_config_set(const char *key, const char *value)
|
|||||||
return git_config_set_multivar(key, value, NULL, 0);
|
return git_config_set_multivar(key, value, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Auxiliary function to sanity-check and split the key into the section
|
||||||
|
* identifier and variable name.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 when there is an invalid character in the key and
|
||||||
|
* -2 if there is no section name in the key.
|
||||||
|
*
|
||||||
|
* store_key - pointer to char* which will hold a copy of the key with
|
||||||
|
* lowercase section and variable name
|
||||||
|
* baselen - pointer to int which will hold the length of the
|
||||||
|
* section + subsection part, can be NULL
|
||||||
|
*/
|
||||||
|
int git_config_parse_key(const char *key, char **store_key, int *baselen_)
|
||||||
|
{
|
||||||
|
int i, dot, baselen;
|
||||||
|
const char *last_dot = strrchr(key, '.');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since "key" actually contains the section name and the real
|
||||||
|
* key name separated by a dot, we have to know where the dot is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (last_dot == NULL || last_dot == key) {
|
||||||
|
error("key does not contain a section: %s", key);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!last_dot[1]) {
|
||||||
|
error("key does not contain variable name: %s", key);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
baselen = last_dot - key;
|
||||||
|
if (baselen_)
|
||||||
|
*baselen_ = baselen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate the key and while at it, lower case it for matching.
|
||||||
|
*/
|
||||||
|
*store_key = xmalloc(strlen(key) + 1);
|
||||||
|
|
||||||
|
dot = 0;
|
||||||
|
for (i = 0; key[i]; i++) {
|
||||||
|
unsigned char c = key[i];
|
||||||
|
if (c == '.')
|
||||||
|
dot = 1;
|
||||||
|
/* Leave the extended basename untouched.. */
|
||||||
|
if (!dot || i > baselen) {
|
||||||
|
if (!iskeychar(c) ||
|
||||||
|
(i == baselen + 1 && !isalpha(c))) {
|
||||||
|
error("invalid key: %s", key);
|
||||||
|
goto out_free_ret_1;
|
||||||
|
}
|
||||||
|
c = tolower(c);
|
||||||
|
} else if (c == '\n') {
|
||||||
|
error("invalid key (newline): %s", key);
|
||||||
|
goto out_free_ret_1;
|
||||||
|
}
|
||||||
|
(*store_key)[i] = c;
|
||||||
|
}
|
||||||
|
(*store_key)[i] = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_free_ret_1:
|
||||||
|
free(*store_key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If value==NULL, unset in (remove from) config,
|
* If value==NULL, unset in (remove from) config,
|
||||||
* if value_regex!=NULL, disregard key/value pairs where value does not match.
|
* if value_regex!=NULL, disregard key/value pairs where value does not match.
|
||||||
@ -1124,59 +1193,23 @@ int git_config_set(const char *key, const char *value)
|
|||||||
int git_config_set_multivar(const char *key, const char *value,
|
int git_config_set_multivar(const char *key, const char *value,
|
||||||
const char *value_regex, int multi_replace)
|
const char *value_regex, int multi_replace)
|
||||||
{
|
{
|
||||||
int i, dot;
|
|
||||||
int fd = -1, in_fd;
|
int fd = -1, in_fd;
|
||||||
int ret;
|
int ret;
|
||||||
char *config_filename;
|
char *config_filename;
|
||||||
struct lock_file *lock = NULL;
|
struct lock_file *lock = NULL;
|
||||||
const char *last_dot = strrchr(key, '.');
|
|
||||||
|
|
||||||
if (config_exclusive_filename)
|
if (config_exclusive_filename)
|
||||||
config_filename = xstrdup(config_exclusive_filename);
|
config_filename = xstrdup(config_exclusive_filename);
|
||||||
else
|
else
|
||||||
config_filename = git_pathdup("config");
|
config_filename = git_pathdup("config");
|
||||||
|
|
||||||
/*
|
/* parse-key returns negative; flip the sign to feed exit(3) */
|
||||||
* Since "key" actually contains the section name and the real
|
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
|
||||||
* key name separated by a dot, we have to know where the dot is.
|
if (ret)
|
||||||
*/
|
|
||||||
|
|
||||||
if (last_dot == NULL) {
|
|
||||||
error("key does not contain a section: %s", key);
|
|
||||||
ret = 2;
|
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
|
||||||
store.baselen = last_dot - key;
|
|
||||||
|
|
||||||
store.multi_replace = multi_replace;
|
store.multi_replace = multi_replace;
|
||||||
|
|
||||||
/*
|
|
||||||
* Validate the key and while at it, lower case it for matching.
|
|
||||||
*/
|
|
||||||
store.key = xmalloc(strlen(key) + 1);
|
|
||||||
dot = 0;
|
|
||||||
for (i = 0; key[i]; i++) {
|
|
||||||
unsigned char c = key[i];
|
|
||||||
if (c == '.')
|
|
||||||
dot = 1;
|
|
||||||
/* Leave the extended basename untouched.. */
|
|
||||||
if (!dot || i > store.baselen) {
|
|
||||||
if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
|
|
||||||
error("invalid key: %s", key);
|
|
||||||
free(store.key);
|
|
||||||
ret = 1;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
c = tolower(c);
|
|
||||||
} else if (c == '\n') {
|
|
||||||
error("invalid key (newline): %s", key);
|
|
||||||
free(store.key);
|
|
||||||
ret = 1;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
store.key[i] = c;
|
|
||||||
}
|
|
||||||
store.key[i] = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The lock serves a purpose in addition to locking: the new
|
* The lock serves a purpose in addition to locking: the new
|
||||||
|
@ -876,11 +876,25 @@ test_expect_success 'check split_cmdline return' "
|
|||||||
"
|
"
|
||||||
|
|
||||||
test_expect_success 'git -c "key=value" support' '
|
test_expect_success 'git -c "key=value" support' '
|
||||||
test "z$(git -c name=value config name)" = zvalue &&
|
|
||||||
test "z$(git -c core.name=value config core.name)" = zvalue &&
|
test "z$(git -c core.name=value config core.name)" = zvalue &&
|
||||||
test "z$(git -c CamelCase=value config camelcase)" = zvalue &&
|
test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
|
||||||
test "z$(git -c flag config --bool flag)" = ztrue &&
|
test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
|
||||||
test_must_fail git -c core.name=value config name
|
test_must_fail git -c name=value config core.name
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'key sanity-checking' '
|
||||||
|
test_must_fail git config foo=bar &&
|
||||||
|
test_must_fail git config foo=.bar &&
|
||||||
|
test_must_fail git config foo.ba=r &&
|
||||||
|
test_must_fail git config foo.1bar &&
|
||||||
|
test_must_fail git config foo."ba
|
||||||
|
z".bar &&
|
||||||
|
test_must_fail git config . false &&
|
||||||
|
test_must_fail git config .foo false &&
|
||||||
|
test_must_fail git config foo. false &&
|
||||||
|
test_must_fail git config .foo. false &&
|
||||||
|
git config foo.bar true &&
|
||||||
|
git config foo."ba =z".bar false
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user