validate ref names
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
diff --git a/include/got_error.h b/include/got_error.h
index f6f99ad..65ff442 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -78,6 +78,7 @@
#define GOT_ERR_UUID_INVALID 62
#define GOT_ERR_UUID 63
#define GOT_ERR_LOCKFILE_TIMEOUT 64
+#define GOT_ERR_BAD_REF_NAME 65
static const struct got_error {
int code;
@@ -146,6 +147,7 @@ static const struct got_error {
{ GOT_ERR_UUID_INVALID, "uuid invalid" },
{ GOT_ERR_UUID, "uuid error" },
{ GOT_ERR_LOCKFILE_TIMEOUT,"lockfile timeout" },
+ { GOT_ERR_BAD_REF_NAME, "bad reference name" },
};
/*
diff --git a/lib/reference.c b/lib/reference.c
index adbeed1..9e96551 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -17,6 +17,7 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <ctype.h>
#include <dirent.h>
#include <sha1.h>
#include <stdio.h>
@@ -36,6 +37,7 @@
#include "got_lib_delta.h"
#include "got_lib_inflate.h"
#include "got_lib_object.h"
+#include "got_lib_lockfile.h"
#ifndef nitems
#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
@@ -159,12 +161,70 @@ get_refs_dir_path(struct got_repository *repo, const char *refname)
return got_repo_get_path_refs(repo);
}
+static int
+is_valid_ref_name(const char *name)
+{
+ const char *s, *slash, *seg;
+ const char forbidden[] = { ' ', '~', '^', ':', '?', '*', '[' , '\\' };
+ const char *forbidden_seq[] = { "//", "..", "@{" };
+ const char *lfs = GOT_LOCKFILE_SUFFIX;
+ const size_t lfs_len = sizeof(GOT_LOCKFILE_SUFFIX) - 1;
+ int i;
+
+ if (name[0] == '@' && name[1] == '\0')
+ return 0;
+
+ slash = strchr(name, '/');
+ if (slash == NULL)
+ return 0;
+
+ s = name;
+ seg = s;
+ if (seg[0] == '\0' || seg[0] == '.' || seg[0] == '/')
+ return 0;
+ while (*s) {
+ for (i = 0; i < nitems(forbidden); i++) {
+ if (*s == forbidden[i])
+ return 0;
+ }
+ for (i = 0; i < nitems(forbidden_seq); i++) {
+ if (s[0] == forbidden_seq[i][0] &&
+ s[1] == forbidden_seq[i][1])
+ return 0;
+ }
+ if (iscntrl((unsigned char)s[0]))
+ return 0;
+ if (s[0] == '.' && s[1] == '\0')
+ return 0;
+ if (*s == '/') {
+ const char *nextseg = s + 1;
+ if (nextseg[0] == '\0' || nextseg[0] == '.' ||
+ nextseg[0] == '/')
+ return 0;
+ if (seg <= s - lfs_len &&
+ strncmp(s - lfs_len, lfs, lfs_len) == 0)
+ return 0;
+ seg = nextseg;
+ }
+ s++;
+ }
+
+ if (seg <= s - lfs_len &&
+ strncmp(s - lfs_len, lfs, lfs_len) == 0)
+ return 0;
+
+ return 1;
+}
+
const struct got_error *
got_ref_alloc(struct got_reference **ref, const char *name,
struct got_object_id *id)
{
const struct got_error *err = NULL;
+ if (!is_valid_ref_name(name))
+ return got_error(GOT_ERR_BAD_REF_NAME);
+
*ref = calloc(1, sizeof(**ref));
if (*ref == NULL)
return got_error_from_errno();