1054
return 0;
1055
}
1056
1057
-static int ensure_valid_ownership(const char *path)
1057
+/*
1058
+ * Check if a repository is safe, by verifying the ownership of the
1059
+ * worktree (if any), the git directory, and the gitfile (if any).
1060
+ *
1061
+ * Exemptions for known-safe repositories can be added via `safe.directory`
1062
+ * config settings; for non-bare repositories, their worktree needs to be
1063
+ * added, for bare ones their git directory.
1064
+ */
1065
+static int ensure_valid_ownership(const char *gitfile,
1066
+ const char *worktree, const char *gitdir)
1067
{
1059
- struct safe_directory_data data = { .path = path };
1068
+ struct safe_directory_data data = {
1069
+ .path = worktree ? worktree : gitdir
1070
+ };
1071
1072
if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
1062
- is_path_owned_by_current_user(path))
1073
+ (!gitfile || is_path_owned_by_current_user(gitfile)) &&
1074
+ (!worktree || is_path_owned_by_current_user(worktree)) &&
1075
+ (!gitdir || is_path_owned_by_current_user(gitdir)))
1076
return 1;
1077
1078
+ /*
1079
+ * data.path is the "path" that identifies the repository and it is
1080
+ * constant regardless of what failed above. data.is_safe should be
1081
+ * initialized to false, and might be changed by the callback.
1082
+ */
1083
read_very_early_config(safe_directory_cb, &data);
1084
1085
return data.is_safe;
1167
current_device = get_device_or_die(dir->buf, NULL, 0);
1168
for (;;) {
1169
int offset = dir->len, error_code = 0;
1170
+ char *gitdir_path = NULL;
1171
+ char *gitfile = NULL;
1172
1173
if (offset > min_offset)
1174
strbuf_addch(dir, '/');
1179
if (die_on_error ||
1180
error_code == READ_GITFILE_ERR_NOT_A_FILE) {
1181
/* NEEDSWORK: fail if .git is not file nor dir */
1162
- if (is_git_directory(dir->buf))
1182
+ if (is_git_directory(dir->buf)) {
1183
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
1184
+ gitdir_path = xstrdup(dir->buf);
1185
+ }
1186
} else if (error_code != READ_GITFILE_ERR_STAT_FAILED)
1187
return GIT_DIR_INVALID_GITFILE;
1166
- }
1188
+ } else
1189
+ gitfile = xstrdup(dir->buf);
1190
+ /*
1191
+ * Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT
1192
+ * to check that directory for a repository.
1193
+ * Now trim that tentative addition away, because we want to
1194
+ * focus on the real directory we are in.
1195
+ */
1196
strbuf_setlen(dir, offset);
1197
if (gitdirenv) {
1169
- if (!ensure_valid_ownership(dir->buf))
1170
- return GIT_DIR_INVALID_OWNERSHIP;
1171
- strbuf_addstr(gitdir, gitdirenv);
1172
- return GIT_DIR_DISCOVERED;
1198
+ enum discovery_result ret;
1199
+
1200
+ if (ensure_valid_ownership(gitfile,
1201
+ dir->buf,
1202
+ (gitdir_path ? gitdir_path : gitdirenv))) {
1203
+ strbuf_addstr(gitdir, gitdirenv);
1204
+ ret = GIT_DIR_DISCOVERED;
1205
+ } else
1206
+ ret = GIT_DIR_INVALID_OWNERSHIP;
1207
+
1208
+ /*
1209
+ * Earlier, during discovery, we might have allocated
1210
+ * string copies for gitdir_path or gitfile so make
1211
+ * sure we don't leak by freeing them now, before
1212
+ * leaving the loop and function.
1213
+ *
1214
+ * Note: gitdirenv will be non-NULL whenever these are
1215
+ * allocated, therefore we need not take care of releasing
1216
+ * them outside of this conditional block.
1217
+ */
1218
+ free(gitdir_path);
1219
+ free(gitfile);
1220
+
1221
+ return ret;
1222
}
1223
1224
if (is_git_directory(dir->buf)) {
1176
- if (!ensure_valid_ownership(dir->buf))
1225
+ if (!ensure_valid_ownership(NULL, NULL, dir->buf))
1226
return GIT_DIR_INVALID_OWNERSHIP;
1227
strbuf_addstr(gitdir, ".");
1228
return GIT_DIR_BARE;
1355
struct strbuf quoted = STRBUF_INIT;
1356
1357
sq_quote_buf_pretty("ed, dir.buf);
1309
- die(_("unsafe repository ('%s' is owned by someone else)\n"
1358
+ die(_("detected dubious ownership in repository at '%s'\n"
1359
"To add an exception for this directory, call:\n"
1360
"\n"
1361
"\tgit config --global --add safe.directory %s"),