Commit 433f0166c946257214758b94d9ddbb8516e4fb98

Edward Thomson 2022-07-04T15:20:59

fs: refactor file ownership checks Refactor the file ownership checks so that callers can provide discrete information about the ownership expectations to a single function.

diff --git a/src/libgit2/config.c b/src/libgit2/config.c
index bce21d7..5c366e2 100644
--- a/src/libgit2/config.c
+++ b/src/libgit2/config.c
@@ -1170,10 +1170,13 @@ int git_config_find_programdata(git_buf *path)
 
 int git_config__find_programdata(git_str *path)
 {
+	git_fs_path_owner_t owner_level =
+		GIT_FS_PATH_OWNER_CURRENT_USER |
+		GIT_FS_PATH_OWNER_ADMINISTRATOR;
 	bool is_safe;
 
 	if (git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA) < 0 ||
-	    git_fs_path_owner_is_system_or_current_user(&is_safe, path->ptr) < 0)
+	    git_fs_path_owner_is(&is_safe, path->ptr, owner_level) < 0)
 		return -1;
 
 	if (!is_safe) {
diff --git a/src/util/fs_path.c b/src/util/fs_path.c
index 58bab70..7ff6b27 100644
--- a/src/util/fs_path.c
+++ b/src/util/fs_path.c
@@ -1879,74 +1879,41 @@ static int file_owner_sid(PSID *out, const char *path)
 	return error;
 }
 
-int git_fs_path_owner_is_current_user(bool *out, const char *path)
+int git_fs_path_owner_is(
+	bool *out,
+	const char *path,
+	git_fs_path_owner_t owner_type)
 {
 	PSID owner_sid = NULL, user_sid = NULL;
-	int error = -1;
+	int error;
 
 	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_CURRENT_USER);
+		*out = ((mock_owner & owner_type) != 0);
 		return 0;
 	}
 
-	if ((error = file_owner_sid(&owner_sid, path)) < 0 ||
-	    (error = current_user_sid(&user_sid)) < 0)
+	if ((error = file_owner_sid(&owner_sid, path)) < 0)
 		goto done;
 
-	*out = EqualSid(owner_sid, user_sid);
-	error = 0;
-
-done:
-	git__free(owner_sid);
-	git__free(user_sid);
-	return error;
-}
-
-int git_fs_path_owner_is_system(bool *out, const char *path)
-{
-	PSID owner_sid;
-
-	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_ADMINISTRATOR);
-		return 0;
-	}
+	if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) {
+		if ((error = current_user_sid(&user_sid)) < 0)
+			goto done;
 
-	if (file_owner_sid(&owner_sid, path) < 0)
-		return -1;
-
-	*out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
-	       IsWellKnownSid(owner_sid, WinLocalSystemSid);
-
-	git__free(owner_sid);
-	return 0;
-}
-
-int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
-{
-	PSID owner_sid = NULL, user_sid = NULL;
-	int error = -1;
-
-	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_ADMINISTRATOR ||
-		        mock_owner == GIT_FS_PATH_OWNER_CURRENT_USER);
-		return 0;
+		if (EqualSid(owner_sid, user_sid)) {
+			*out = true;
+			goto done;
+		}
 	}
 
-	if (file_owner_sid(&owner_sid, path) < 0)
-		goto done;
-
-	if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
-	    IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
-		*out = 1;
-		error = 0;
-		goto done;
+	if ((owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0) {
+		if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
+		    IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
+			*out = true;
+			goto done;
+		}
 	}
 
-	if (current_user_sid(&user_sid) < 0)
-		goto done;
-
-	*out = EqualSid(owner_sid, user_sid);
-	error = 0;
+	*out = false;
 
 done:
 	git__free(owner_sid);
@@ -1956,10 +1923,25 @@ done:
 
 #else
 
-static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len)
+int git_fs_path_owner_is(
+	bool *out,
+	const char *path,
+	git_fs_path_owner_t owner_type)
 {
+	uid_t uids[2] = { 0 };
+	size_t uid_count = 0, i;
 	struct stat st;
-	size_t i;
+
+	if (mock_owner) {
+		*out = ((mock_owner & owner_type) != 0);
+		return 0;
+	}
+
+	if (owner_type & GIT_FS_PATH_OWNER_CURRENT_USER)
+		uids[uid_count++] = geteuid();
+
+	if (owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR)
+		uids[uid_count++] = 0;
 
 	*out = false;
 
@@ -1971,7 +1953,7 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid
 		return -1;
 	}
 
-	for (i = 0; i < uids_len; i++) {
+	for (i = 0; i < uid_count; i++) {
 		if (uids[i] == st.st_uid) {
 			*out = true;
 			break;
@@ -1980,46 +1962,18 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid
 
 	return 0;
 }
+#endif
 
 int git_fs_path_owner_is_current_user(bool *out, const char *path)
 {
-	uid_t userid = geteuid();
-
-	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_CURRENT_USER);
-		return 0;
-	}
-
-	return fs_path_owner_is(out, path, &userid, 1);
+	return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_CURRENT_USER);
 }
 
 int git_fs_path_owner_is_system(bool *out, const char *path)
 {
-	uid_t userid = 0;
-
-	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_ADMINISTRATOR);
-		return 0;
-	}
-
-	return fs_path_owner_is(out, path, &userid, 1);
+	return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_ADMINISTRATOR);
 }
 
-int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
-{
-	uid_t userids[2] = { geteuid(), 0 };
-
-	if (mock_owner) {
-		*out = (mock_owner == GIT_FS_PATH_OWNER_ADMINISTRATOR ||
-		        mock_owner == GIT_FS_PATH_OWNER_CURRENT_USER);
-		return 0;
-	}
-
-	return fs_path_owner_is(out, path, userids, 2);
-}
-
-#endif
-
 int git_fs_path_find_executable(git_str *fullpath, const char *executable)
 {
 #ifdef GIT_WIN32
diff --git a/src/util/fs_path.h b/src/util/fs_path.h
index ae28479..2dc6d56 100644
--- a/src/util/fs_path.h
+++ b/src/util/fs_path.h
@@ -740,15 +740,8 @@ typedef enum {
 	/** The file must be owned by the system account. */
 	GIT_FS_PATH_OWNER_ADMINISTRATOR = (1 << 1),
 
-	/**
-	 * The file may be owned by a system account if the current
-	 * user is in an administrator group. Windows only; this is
-	 * a noop on non-Windows systems.
-	 */
-	GIT_FS_PATH_OWNER_CURRENT_USER_IS_ADMINISTRATOR = (1 << 2),
-
 	/** The file may be owned by another user. */
-	GIT_FS_PATH_OWNER_OTHER = (1 << 4)
+	GIT_FS_PATH_OWNER_OTHER = (1 << 2)
 } git_fs_path_owner_t;
 
 /**
@@ -758,6 +751,12 @@ typedef enum {
  */
 void git_fs_path__set_owner(git_fs_path_owner_t owner);
 
+/** Verify that the file in question is owned by the given owner. */
+int git_fs_path_owner_is(
+	bool *out,
+	const char *path,
+	git_fs_path_owner_t owner_type);
+
 /**
  * Verify that the file in question is owned by an administrator or system
  * account.
@@ -771,12 +770,6 @@ int git_fs_path_owner_is_system(bool *out, const char *path);
 int git_fs_path_owner_is_current_user(bool *out, const char *path);
 
 /**
- * Verify that the file in question is owned by an administrator or system
- * account _or_ the current user;
- */
-int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path);
-
-/**
  * Search the current PATH for the given executable, returning the full
  * path if it is found.
  */