]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Add a function to determine whether a path is owned by the current user
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Wed, 2 Mar 2022 10:06:24 +0000 (11:06 +0100)
committerJohannes Schindelin <johannes.schindelin@gmx.de>
Mon, 21 Mar 2022 12:16:26 +0000 (13:16 +0100)
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
compat/mingw.h
git-compat-util.h

index abb4d26ce940f3bd8cc3c60d8f4b76e0d885fbd0..38ac35913df78ef06aef4a8a49b56aedb5ab489c 100644 (file)
@@ -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;
index af8eddd73edb2b1d19caddad4732aa7a370d0cc0..f6bab548f4cf44fec9e39a09113f028efdba97e4 100644 (file)
@@ -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.
  *
index 3da9f975e27712e866688cb6da01383ec684c5d9..63ba89dd31d947ef0c327cf6f1dd2de45965443a 100644 (file)
@@ -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)
 {