Skip to content

Commit

Permalink
fs: refactor file ownership checks
Browse files Browse the repository at this point in the history
Refactor the file ownership checks so that callers can provide discrete
information about the ownership expectations to a single function.
  • Loading branch information
ethomson committed Jul 7, 2022
1 parent df354ec commit 433f016
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 103 deletions.
5 changes: 4 additions & 1 deletion src/libgit2/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
130 changes: 42 additions & 88 deletions src/util/fs_path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -1956,10 +1923,25 @@ int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)

#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;

Expand All @@ -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;
Expand All @@ -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
Expand Down
21 changes: 7 additions & 14 deletions src/util/fs_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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.
Expand All @@ -770,12 +769,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.
Expand Down

0 comments on commit 433f016

Please sign in to comment.