175 lines
4.9 KiB
Diff
175 lines
4.9 KiB
Diff
From bdc77d1d685be9c10b88abb281a42bc620548595 Mon Sep 17 00:00:00 2001
|
|
From: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
Date: Wed, 2 Mar 2022 11:06:24 +0100
|
|
Subject: [PATCH] Add a function to determine whether a path is owned by the
|
|
current user
|
|
|
|
This function will be used in the next commit to prevent
|
|
`setup_git_directory()` from discovering a repository in a directory
|
|
that is owned by someone other than the current user.
|
|
|
|
Note: We cannot simply use `st.st_uid` on Windows just like we do on
|
|
Linux and other Unix-like platforms: according to
|
|
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions
|
|
this field is always zero on Windows (because Windows' idea of a user ID
|
|
does not fit into a single numerical value). Therefore, we have to do
|
|
something a little involved to replicate the same functionality there.
|
|
|
|
Also note: On Windows, a user's home directory is not actually owned by
|
|
said user, but by the administrator. For all practical purposes, it is
|
|
under the user's control, though, therefore we pretend that it is owned
|
|
by the user.
|
|
|
|
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
---
|
|
compat/mingw.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
compat/mingw.h | 7 ++++
|
|
git-compat-util.h | 12 +++++++
|
|
3 files changed, 106 insertions(+)
|
|
|
|
diff --git a/compat/mingw.c b/compat/mingw.c
|
|
index abb4d26ce940f3..38ac35913df78e 100644
|
|
--- a/compat/mingw.c
|
|
+++ b/compat/mingw.c
|
|
@@ -1,5 +1,6 @@
|
|
#include "../git-compat-util.h"
|
|
#include "win32.h"
|
|
+#include <aclapi.h>
|
|
#include <conio.h>
|
|
#include <wchar.h>
|
|
#include "../strbuf.h"
|
|
@@ -2601,6 +2602,92 @@ static void setup_windows_environment(void)
|
|
}
|
|
}
|
|
|
|
+static PSID get_current_user_sid(void)
|
|
+{
|
|
+ HANDLE token;
|
|
+ DWORD len = 0;
|
|
+ PSID result = NULL;
|
|
+
|
|
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
|
|
+ return NULL;
|
|
+
|
|
+ if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
|
|
+ TOKEN_USER *info = xmalloc((size_t)len);
|
|
+ if (GetTokenInformation(token, TokenUser, info, len, &len)) {
|
|
+ len = GetLengthSid(info->User.Sid);
|
|
+ result = xmalloc(len);
|
|
+ if (!CopySid(len, result, info->User.Sid)) {
|
|
+ error(_("failed to copy SID (%ld)"),
|
|
+ GetLastError());
|
|
+ FREE_AND_NULL(result);
|
|
+ }
|
|
+ }
|
|
+ FREE_AND_NULL(info);
|
|
+ }
|
|
+ CloseHandle(token);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+int is_path_owned_by_current_sid(const char *path)
|
|
+{
|
|
+ WCHAR wpath[MAX_PATH];
|
|
+ PSID sid = NULL;
|
|
+ PSECURITY_DESCRIPTOR descriptor = NULL;
|
|
+ DWORD err;
|
|
+
|
|
+ static wchar_t home[MAX_PATH];
|
|
+
|
|
+ int result = 0;
|
|
+
|
|
+ if (xutftowcs_path(wpath, path) < 0)
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * On Windows, the home directory is owned by the administrator, but for
|
|
+ * all practical purposes, it belongs to the user. Do pretend that it is
|
|
+ * owned by the user.
|
|
+ */
|
|
+ if (!*home) {
|
|
+ DWORD size = ARRAY_SIZE(home);
|
|
+ DWORD len = GetEnvironmentVariableW(L"HOME", home, size);
|
|
+ if (!len || len > size)
|
|
+ wcscpy(home, L"::N/A::");
|
|
+ }
|
|
+ if (!wcsicmp(wpath, home))
|
|
+ return 1;
|
|
+
|
|
+ /* Get the owner SID */
|
|
+ err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
|
|
+ OWNER_SECURITY_INFORMATION |
|
|
+ DACL_SECURITY_INFORMATION,
|
|
+ &sid, NULL, NULL, NULL, &descriptor);
|
|
+
|
|
+ if (err != ERROR_SUCCESS)
|
|
+ error(_("failed to get owner for '%s' (%ld)"), path, err);
|
|
+ else if (sid && IsValidSid(sid)) {
|
|
+ /* Now, verify that the SID matches the current user's */
|
|
+ static PSID current_user_sid;
|
|
+
|
|
+ if (!current_user_sid)
|
|
+ current_user_sid = get_current_user_sid();
|
|
+
|
|
+ if (current_user_sid &&
|
|
+ IsValidSid(current_user_sid) &&
|
|
+ EqualSid(sid, current_user_sid))
|
|
+ result = 1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We can release the security descriptor struct only now because `sid`
|
|
+ * actually points into this struct.
|
|
+ */
|
|
+ if (descriptor)
|
|
+ LocalFree(descriptor);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
int is_valid_win32_path(const char *path, int allow_literal_nul)
|
|
{
|
|
const char *p = path;
|
|
diff --git a/compat/mingw.h b/compat/mingw.h
|
|
index af8eddd73edb2b..f6bab548f4cf44 100644
|
|
--- a/compat/mingw.h
|
|
+++ b/compat/mingw.h
|
|
@@ -452,6 +452,13 @@ char *mingw_query_user_email(void);
|
|
#include <inttypes.h>
|
|
#endif
|
|
|
|
+/**
|
|
+ * Verifies that the specified path is owned by the user running the
|
|
+ * current process.
|
|
+ */
|
|
+int is_path_owned_by_current_sid(const char *path);
|
|
+#define is_path_owned_by_current_user is_path_owned_by_current_sid
|
|
+
|
|
/**
|
|
* Verifies that the given path is a valid one on Windows.
|
|
*
|
|
diff --git a/git-compat-util.h b/git-compat-util.h
|
|
index 3da9f975e27712..63ba89dd31d947 100644
|
|
--- a/git-compat-util.h
|
|
+++ b/git-compat-util.h
|
|
@@ -392,6 +392,18 @@ static inline int git_offset_1st_component(const char *path)
|
|
#define is_valid_path(path) 1
|
|
#endif
|
|
|
|
+#ifndef is_path_owned_by_current_user
|
|
+static inline int is_path_owned_by_current_uid(const char *path)
|
|
+{
|
|
+ struct stat st;
|
|
+ if (lstat(path, &st))
|
|
+ return 0;
|
|
+ return st.st_uid == geteuid();
|
|
+}
|
|
+
|
|
+#define is_path_owned_by_current_user is_path_owned_by_current_uid
|
|
+#endif
|
|
+
|
|
#ifndef find_last_dir_sep
|
|
static inline char *git_find_last_dir_sep(const char *path)
|
|
{
|