@@ -2024,78 +2024,237 @@ 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+ static git_path__mock_owner_t mock_owner = GIT_PATH_MOCK_OWNER_NONE ;
2028+
2029+ void git_path__set_owner (git_path__mock_owner_t owner )
2030+ {
2031+ mock_owner = owner ;
2032+ }
2033+
2034+ #ifdef GIT_WIN32
2035+ static PSID * sid_dup (PSID sid )
2036+ {
2037+ DWORD len ;
2038+ PSID dup ;
2039+
2040+ len = GetLengthSid (sid );
2041+
2042+ if ((dup = git__malloc (len )) == NULL )
2043+ return NULL ;
2044+
2045+ if (!CopySid (len , dup , sid )) {
2046+ git_error_set (GIT_ERROR_OS , "could not duplicate sid" );
2047+ git__free (dup );
2048+ return NULL ;
2049+ }
2050+
2051+ return dup ;
2052+ }
2053+
2054+ static int current_user_sid (PSID * out )
20282055{
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 ;
20372056 TOKEN_USER * info = NULL ;
2038- DWORD err , len ;
2039- int ret ;
2057+ HANDLE token = NULL ;
2058+ DWORD len = 0 ;
2059+ int error = -1 ;
20402060
2041- if (git_win32_path_from_utf8 (buf , path ) < 0 )
2042- return -1 ;
2061+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY , & token )) {
2062+ git_error_set (GIT_ERROR_OS , "could not lookup process information" );
2063+ goto done ;
2064+ }
2065+
2066+ if (GetTokenInformation (token , TokenUser , NULL , 0 , & len ) ||
2067+ GetLastError () != ERROR_INSUFFICIENT_BUFFER ) {
2068+ git_error_set (GIT_ERROR_OS , "could not lookup token metadata" );
2069+ goto done ;
2070+ }
20432071
2044- err = GetNamedSecurityInfoW (buf , SE_FILE_OBJECT ,
2045- OWNER_SECURITY_INFORMATION |
2046- DACL_SECURITY_INFORMATION ,
2047- & owner_sid , NULL , NULL , NULL , & descriptor );
2072+ info = git__malloc (len );
2073+ GIT_ERROR_CHECK_ALLOC (info );
20482074
2049- if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ) {
2050- ret = GIT_ENOTFOUND ;
2051- goto cleanup ;
2075+ if (! GetTokenInformation ( token , TokenUser , info , len , & len ) ) {
2076+ git_error_set ( GIT_ERROR_OS , "could not lookup current user" ) ;
2077+ goto done ;
20522078 }
20532079
2054- if (err != ERROR_SUCCESS ) {
2080+ if ((* out = sid_dup (info -> User .Sid )))
2081+ error = 0 ;
2082+
2083+ done :
2084+ if (token )
2085+ CloseHandle (token );
2086+
2087+ git__free (info );
2088+ return error ;
2089+ }
2090+
2091+ static int file_owner_sid (PSID * out , const char * path )
2092+ {
2093+ git_win32_path path_w32 ;
2094+ PSECURITY_DESCRIPTOR descriptor = NULL ;
2095+ PSID owner_sid ;
2096+ DWORD ret ;
2097+ int error = -1 ;
2098+
2099+ if (git_win32_path_from_utf8 (path_w32 , path ) < 0 )
2100+ return -1 ;
2101+
2102+ ret = GetNamedSecurityInfoW (path_w32 , SE_FILE_OBJECT ,
2103+ OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION ,
2104+ & owner_sid , NULL , NULL , NULL , & descriptor );
2105+
2106+ if (ret == ERROR_FILE_NOT_FOUND || ret == ERROR_PATH_NOT_FOUND )
2107+ error = GIT_ENOTFOUND ;
2108+ else if (ret != ERROR_SUCCESS )
20552109 git_error_set (GIT_ERROR_OS , "failed to get security information" );
2056- ret = GIT_ERROR ;
2057- goto cleanup ;
2110+ else if (!IsValidSid (owner_sid ))
2111+ git_error_set (GIT_ERROR_OS , "file owner is not valid" );
2112+ else if ((* out = sid_dup (owner_sid )))
2113+ error = 0 ;
2114+
2115+ if (descriptor )
2116+ LocalFree (descriptor );
2117+
2118+ return error ;
2119+ }
2120+
2121+ int git_path_owner_is_current_user (bool * out , const char * path )
2122+ {
2123+ PSID owner_sid = NULL , user_sid = NULL ;
2124+ int error = -1 ;
2125+
2126+ if (mock_owner ) {
2127+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER );
2128+ return 0 ;
2129+ }
2130+
2131+ if ((error = file_owner_sid (& owner_sid , path )) < 0 ||
2132+ (error = current_user_sid (& user_sid )) < 0 )
2133+ goto done ;
2134+
2135+ * out = EqualSid (owner_sid , user_sid );
2136+ error = 0 ;
2137+
2138+ done :
2139+ git__free (owner_sid );
2140+ git__free (user_sid );
2141+ return error ;
2142+ }
2143+
2144+ int git_path_owner_is_system (bool * out , const char * path )
2145+ {
2146+ PSID owner_sid ;
2147+
2148+ if (mock_owner ) {
2149+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM );
2150+ return 0 ;
20582151 }
20592152
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 ;
2153+ if (file_owner_sid (& owner_sid , path ) < 0 )
2154+ return -1 ;
2155+
2156+ * out = IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
2157+ IsWellKnownSid (owner_sid , WinLocalSystemSid );
2158+
2159+ git__free (owner_sid );
2160+ return 0 ;
2161+ }
2162+
2163+ int git_path_owner_is_system_or_current_user (bool * out , const char * path )
2164+ {
2165+ PSID owner_sid = NULL , user_sid = NULL ;
2166+ int error = -1 ;
2167+
2168+ if (mock_owner ) {
2169+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM ||
2170+ mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER );
2171+ return 0 ;
20642172 }
20652173
2174+ if (file_owner_sid (& owner_sid , path ) < 0 )
2175+ goto done ;
2176+
20662177 if (IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
20672178 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 ;
2179+ * out = 1 ;
2180+ error = 0 ;
2181+ goto done ;
2182+ }
2183+
2184+ if (current_user_sid (& user_sid ) < 0 )
2185+ goto done ;
2186+
2187+ * out = EqualSid (owner_sid , user_sid );
2188+ error = 0 ;
2189+
2190+ done :
2191+ git__free (owner_sid );
2192+ git__free (user_sid );
2193+ return error ;
2194+ }
2195+
2196+ #else
2197+
2198+ static int path_owner_is (bool * out , const char * path , uid_t * uids , size_t uids_len )
2199+ {
2200+ struct stat st ;
2201+ size_t i ;
2202+
2203+ * out = false;
2204+
2205+ if (p_lstat (path , & st ) != 0 ) {
2206+ if (errno == ENOENT )
2207+ return GIT_ENOTFOUND ;
2208+
2209+ git_error_set (GIT_ERROR_OS , "could not stat '%s'" , path );
2210+ return -1 ;
2211+ }
2212+
2213+ for (i = 0 ; i < uids_len ; i ++ ) {
2214+ if (uids [i ] == st .st_uid ) {
2215+ * out = true;
2216+ break ;
20802217 }
20812218 }
20822219
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 ;
2220+ return 0 ;
2221+ }
2222+
2223+ int git_path_owner_is_current_user (bool * out , const char * path )
2224+ {
2225+ uid_t userid = geteuid ();
2226+
2227+ if (mock_owner ) {
2228+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER );
2229+ return 0 ;
20922230 }
2093- git__free (info );
20942231
2095- cleanup :
2096- if (descriptor )
2097- LocalFree (descriptor );
2232+ return path_owner_is (out , path , & userid , 1 );
2233+ }
20982234
2099- return ret ;
2100- #endif
2235+ int git_path_owner_is_system (bool * out , const char * path )
2236+ {
2237+ uid_t userid = 0 ;
2238+
2239+ if (mock_owner ) {
2240+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM );
2241+ return 0 ;
2242+ }
2243+
2244+ return path_owner_is (out , path , & userid , 1 );
2245+ }
2246+
2247+ int git_path_owner_is_system_or_current_user (bool * out , const char * path )
2248+ {
2249+ uid_t userids [2 ] = { geteuid (), 0 };
2250+
2251+ if (mock_owner ) {
2252+ * out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM ||
2253+ mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER );
2254+ return 0 ;
2255+ }
2256+
2257+ return path_owner_is (out , path , userids , 2 );
21012258}
2259+
2260+ #endif
0 commit comments