@@ -2024,78 +2024,237 @@ bool git_path_supports_symlinks(const char *dir)
2024
2024
return supported ;
2025
2025
}
2026
2026
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 )
2028
2055
{
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
2056
TOKEN_USER * info = NULL ;
2038
- DWORD err , len ;
2039
- int ret ;
2057
+ HANDLE token = NULL ;
2058
+ DWORD len = 0 ;
2059
+ int error = -1 ;
2040
2060
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
+ }
2043
2071
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 );
2048
2074
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 ;
2052
2078
}
2053
2079
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 )
2055
2109
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 ;
2058
2151
}
2059
2152
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 ;
2064
2172
}
2065
2173
2174
+ if (file_owner_sid (& owner_sid , path ) < 0 )
2175
+ goto done ;
2176
+
2066
2177
if (IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) ||
2067
2178
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 ;
2080
2217
}
2081
2218
}
2082
2219
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 ;
2092
2230
}
2093
- git__free (info );
2094
2231
2095
- cleanup :
2096
- if (descriptor )
2097
- LocalFree (descriptor );
2232
+ return path_owner_is (out , path , & userid , 1 );
2233
+ }
2098
2234
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 );
2101
2258
}
2259
+
2260
+ #endif
0 commit comments