diff options
| -rw-r--r-- | include/git2/common.h | 10 | ||||
| -rw-r--r-- | src/refs.c | 29 | ||||
| -rw-r--r-- | src/refs.h | 3 | ||||
| -rw-r--r-- | src/settings.c | 5 |
4 files changed, 41 insertions, 6 deletions
diff --git a/include/git2/common.h b/include/git2/common.h index 99c99812b..5be7fb632 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -175,6 +175,7 @@ typedef enum { GIT_OPT_SET_SSL_CERT_LOCATIONS, GIT_OPT_SET_USER_AGENT, GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, + GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, GIT_OPT_SET_SSL_CIPHERS, GIT_OPT_GET_USER_AGENT, } git_libgit2_opt_t; @@ -289,6 +290,15 @@ typedef enum { * > will be validated when creating a new commit. This defaults * > to enabled. * + * * opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled) + * + * > Validate the target of a symbolic ref when creating it. For + * > example, `foobar` is not a valid ref, therefore `foobar` is + * > not a valid target for a symbolic ref by default, whereas + * > `refs/heads/foobar` is. Disabling this bypasses validation + * > so that an arbitrary strings such as `foobar` can be used + * > for a symbolic ref target. This defaults to enabled. + * * * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers) * * > Set the SSL ciphers use for HTTPS connections. diff --git a/src/refs.c b/src/refs.c index dbc7e5e8e..140b175af 100644 --- a/src/refs.c +++ b/src/refs.c @@ -24,6 +24,8 @@ #include <git2/signature.h> #include <git2/commit.h> +bool git_reference__enable_symbolic_ref_target_validation = true; + GIT__USE_STRMAP #define DEFAULT_NESTING_LEVEL 5 @@ -178,7 +180,8 @@ int git_reference_name_to_id( static int reference_normalize_for_repo( git_refname_t out, git_repository *repo, - const char *name) + const char *name, + bool validate) { int precompose; unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL; @@ -187,6 +190,9 @@ static int reference_normalize_for_repo( precompose) flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE; + if (!validate) + flags |= GIT_REF_FORMAT__VALIDATION_DISABLE; + return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); } @@ -213,7 +219,7 @@ int git_reference_lookup_resolved( scan_type = GIT_REF_SYMBOLIC; - if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0) + if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0) return error; if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) @@ -383,7 +389,7 @@ static int reference__create( if (ref_out) *ref_out = NULL; - error = reference_normalize_for_repo(normalized, repo, name); + error = reference_normalize_for_repo(normalized, repo, name, true); if (error < 0) return error; @@ -404,7 +410,10 @@ static int reference__create( } else { git_refname_t normalized_target; - if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0) + error = reference_normalize_for_repo(normalized_target, repo, + symbolic, git_reference__enable_symbolic_ref_target_validation); + + if (error < 0) return error; ref = git_reference__alloc_symbolic(normalized, normalized_target); @@ -583,7 +592,7 @@ static int reference__rename(git_reference **out, git_reference *ref, const char assert(ref && new_name && signature); if ((error = reference_normalize_for_repo( - normalized, git_reference_owner(ref), new_name)) < 0) + normalized, git_reference_owner(ref), new_name, true)) < 0) return error; @@ -876,6 +885,7 @@ int git_reference__normalize_name( int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; unsigned int process_flags; bool normalize = (buf != NULL); + bool validate = (flags & GIT_REF_FORMAT__VALIDATION_DISABLE) == 0; #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; @@ -886,7 +896,7 @@ int git_reference__normalize_name( process_flags = flags; current = (char *)name; - if (*current == '/') + if (validate && *current == '/') goto cleanup; if (normalize) @@ -902,6 +912,13 @@ int git_reference__normalize_name( } #endif + if (!validate) { + git_buf_sets(buf, current); + + error = git_buf_oom(buf) ? -1 : 0; + goto cleanup; + } + while (true) { segment_len = ensure_segment_validity(current); if (segment_len < 0) { diff --git a/src/refs.h b/src/refs.h index fda9532de..80e655af7 100644 --- a/src/refs.h +++ b/src/refs.h @@ -15,6 +15,8 @@ #include "buffer.h" #include "oid.h" +extern bool git_reference__enable_symbolic_ref_target_validation; + #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" @@ -53,6 +55,7 @@ #define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE #define GIT_REF_FORMAT__PRECOMPOSE_UNICODE (1u << 16) +#define GIT_REF_FORMAT__VALIDATION_DISABLE (1u << 15) #define GIT_REFNAME_MAX 1024 diff --git a/src/settings.c b/src/settings.c index 980233d88..222bd6b8e 100644 --- a/src/settings.c +++ b/src/settings.c @@ -15,6 +15,7 @@ #include "cache.h" #include "global.h" #include "object.h" +#include "refs.h" void git_libgit2_version(int *major, int *minor, int *rev) { @@ -193,6 +194,10 @@ int git_libgit2_opts(int key, ...) git_object__strict_input_validation = (va_arg(ap, int) != 0); break; + case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: + git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); + break; + case GIT_OPT_SET_SSL_CIPHERS: #ifdef GIT_OPENSSL { |
