@@ -2024,78 +2024,195 @@ bool git_path_supports_symlinks(const char *dir)
20242024 return supported ;
20252025}
20262026
2027- int git_path_validate_system_file_ownership (const char * path )
2027+ #ifdef GIT_WIN32
2028+ static PSID * sid_dup (PSID sid )
20282029{
2029- #ifndef GIT_WIN32
2030- GIT_UNUSED (path );
2031- return GIT_OK ;
2032- #else
2033- git_win32_path buf ;
2034- PSID owner_sid ;
2035- PSECURITY_DESCRIPTOR descriptor = NULL ;
2036- HANDLE token ;
2037- TOKEN_USER * info = NULL ;
2038- DWORD err , len ;
2039- int ret ;
2030+ DWORD len ;
2031+ PSID dup ;
20402032
2041- if (git_win32_path_from_utf8 (buf , path ) < 0 )
2042- return -1 ;
2033+ len = GetLengthSid (sid );
20432034
2044- err = GetNamedSecurityInfoW (buf , SE_FILE_OBJECT ,
2045- OWNER_SECURITY_INFORMATION |
2046- DACL_SECURITY_INFORMATION ,
2047- & owner_sid , NULL , NULL , NULL , & descriptor );
2035+ if ((dup = git__malloc (len )) == NULL )
2036+ return NULL ;
20482037
2049- if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ) {
2050- ret = GIT_ENOTFOUND ;
2051- goto cleanup ;
2038+ if (!CopySid (len , dup , sid )) {
2039+ git_error_set (GIT_ERROR_OS , "could not duplicate sid" );
2040+ git__free (dup );
2041+ return NULL ;
20522042 }
20532043
2054- if (err != ERROR_SUCCESS ) {
2055- git_error_set (GIT_ERROR_OS , "failed to get security information" );
2056- ret = GIT_ERROR ;
2057- goto cleanup ;
2058- }
2044+ return dup ;
2045+ }
2046+
2047+ static int current_user_sid (PSID * out )
2048+ {
2049+ TOKEN_USER * info = NULL ;
2050+ HANDLE token = NULL ;
2051+ DWORD len = 0 ;
2052+ int error = -1 ;
20592053
2060- if (!IsValidSid (owner_sid )) {
2061- git_error_set (GIT_ERROR_INVALID , "programdata configuration file owner is unknown" );
2062- ret = GIT_ERROR ;
2063- goto cleanup ;
2054+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY , & token )) {
2055+ git_error_set (GIT_ERROR_OS , "could not lookup process information" );
2056+ goto done ;
20642057 }
20652058
2066- if (IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
2067- IsWellKnownSid (owner_sid , WinLocalSystemSid )) {
2068- ret = GIT_OK ;
2069- goto cleanup ;
2070- }
2071-
2072- /* Obtain current user's SID */
2073- if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY , & token ) &&
2074- !GetTokenInformation (token , TokenUser , NULL , 0 , & len )) {
2075- info = git__malloc (len );
2076- GIT_ERROR_CHECK_ALLOC (info );
2077- if (!GetTokenInformation (token , TokenUser , info , len , & len )) {
2078- git__free (info );
2079- info = NULL ;
2080- }
2059+ if (GetTokenInformation (token , TokenUser , NULL , 0 , & len ) ||
2060+ GetLastError () != ERROR_INSUFFICIENT_BUFFER ) {
2061+ git_error_set (GIT_ERROR_OS , "could not lookup token metadata" );
2062+ goto done ;
20812063 }
20822064
2083- /*
2084- * If the file is owned by the same account that is running the current
2085- * process, it's okay to read from that file.
2086- */
2087- if (info && EqualSid (owner_sid , info -> User .Sid ))
2088- ret = GIT_OK ;
2089- else {
2090- git_error_set (GIT_ERROR_INVALID , "programdata configuration file owner is not valid" );
2091- ret = GIT_ERROR ;
2065+ info = git__malloc (len );
2066+ GIT_ERROR_CHECK_ALLOC (info );
2067+
2068+ if (!GetTokenInformation (token , TokenUser , info , len , & len )) {
2069+ git_error_set (GIT_ERROR_OS , "could not lookup current user" );
2070+ goto done ;
20922071 }
2072+
2073+ if ((* out = sid_dup (info -> User .Sid )))
2074+ error = 0 ;
2075+
2076+ done :
2077+ if (token )
2078+ CloseHandle (token );
2079+
20932080 git__free (info );
2081+ return error ;
2082+ }
2083+
2084+ static int file_owner_sid (PSID * out , const char * path )
2085+ {
2086+ git_win32_path path_w32 ;
2087+ PSECURITY_DESCRIPTOR descriptor = NULL ;
2088+ PSID owner_sid ;
2089+ DWORD ret ;
2090+ int error = -1 ;
2091+
2092+ if (git_win32_path_from_utf8 (path_w32 , path ) < 0 )
2093+ return -1 ;
2094+
2095+ ret = GetNamedSecurityInfoW (path_w32 , SE_FILE_OBJECT ,
2096+ OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION ,
2097+ & owner_sid , NULL , NULL , NULL , & descriptor );
2098+
2099+ if (ret == ERROR_FILE_NOT_FOUND || ret == ERROR_PATH_NOT_FOUND )
2100+ error = GIT_ENOTFOUND ;
2101+ else if (ret != ERROR_SUCCESS )
2102+ git_error_set (GIT_ERROR_OS , "failed to get security information" );
2103+ else if (!IsValidSid (owner_sid ))
2104+ git_error_set (GIT_ERROR_OS , "file owner is not valid" );
2105+ else if ((* out = sid_dup (owner_sid )))
2106+ error = 0 ;
20942107
2095- cleanup :
20962108 if (descriptor )
20972109 LocalFree (descriptor );
20982110
2099- return ret ;
2100- #endif
2111+ return error ;
21012112}
2113+
2114+ int git_path_owner_is_current_user (bool * out , const char * path )
2115+ {
2116+ PSID owner_sid = NULL , user_sid = NULL ;
2117+ int error = -1 ;
2118+
2119+ if ((error = file_owner_sid (& owner_sid , path )) < 0 ||
2120+ (error = current_user_sid (& user_sid )) < 0 )
2121+ goto done ;
2122+
2123+ * out = EqualSid (owner_sid , user_sid );
2124+ error = 0 ;
2125+
2126+ done :
2127+ git__free (owner_sid );
2128+ git__free (user_sid );
2129+ return error ;
2130+ }
2131+
2132+ int git_path_owner_is_system (bool * out , const char * path )
2133+ {
2134+ PSID owner_sid ;
2135+
2136+ if (file_owner_sid (& owner_sid , path ) < 0 )
2137+ return -1 ;
2138+
2139+ * out = IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
2140+ IsWellKnownSid (owner_sid , WinLocalSystemSid );
2141+
2142+ git__free (owner_sid );
2143+ return 0 ;
2144+ }
2145+
2146+ int git_path_owner_is_system_or_current_user (bool * out , const char * path )
2147+ {
2148+ PSID owner_sid = NULL , user_sid = NULL ;
2149+ int error = -1 ;
2150+
2151+ if (file_owner_sid (& owner_sid , path ) < 0 )
2152+ goto done ;
2153+
2154+ if (IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
2155+ IsWellKnownSid (owner_sid , WinLocalSystemSid )) {
2156+ * out = 1 ;
2157+ error = 0 ;
2158+ goto done ;
2159+ }
2160+
2161+ if (current_user_sid (& user_sid ) < 0 )
2162+ goto done ;
2163+
2164+ * out = EqualSid (owner_sid , user_sid );
2165+ error = 0 ;
2166+
2167+ done :
2168+ git__free (owner_sid );
2169+ git__free (user_sid );
2170+ return error ;
2171+ }
2172+
2173+ #else
2174+
2175+ static int path_owner_is (bool * out , const char * path , uid_t * uids , size_t uids_len )
2176+ {
2177+ struct stat st ;
2178+ size_t i ;
2179+
2180+ * out = false;
2181+
2182+ if (p_lstat (path , & st ) != 0 ) {
2183+ if (errno == ENOENT )
2184+ return GIT_ENOTFOUND ;
2185+
2186+ git_error_set (GIT_ERROR_OS , "could not stat '%s'" , path );
2187+ return -1 ;
2188+ }
2189+
2190+ for (i = 0 ; i < uids_len ; i ++ ) {
2191+ if (uids [i ] == st .st_uid ) {
2192+ * out = true;
2193+ break ;
2194+ }
2195+ }
2196+
2197+ return 0 ;
2198+ }
2199+
2200+ int git_path_owner_is_current_user (bool * out , const char * path )
2201+ {
2202+ uid_t userid = geteuid ();
2203+ return path_owner_is (out , path , & userid , 1 );
2204+ }
2205+
2206+ int git_path_owner_is_system (bool * out , const char * path )
2207+ {
2208+ uid_t userid = 0 ;
2209+ return path_owner_is (out , path , & userid , 1 );
2210+ }
2211+
2212+ int git_path_owner_is_system_or_current_user (bool * out , const char * path )
2213+ {
2214+ uid_t userids [2 ] = { geteuid (), 0 };
2215+ return path_owner_is (out , path , userids , 2 );
2216+ }
2217+
2218+ #endif
0 commit comments