|
3 | 3 | #include <conio.h>
|
4 | 4 | #include <wchar.h>
|
5 | 5 | #include <winioctl.h>
|
| 6 | +#include <aclapi.h> |
| 7 | +#include <sddl.h> |
6 | 8 | #include "../strbuf.h"
|
7 | 9 | #include "../run-command.h"
|
8 | 10 | #include "../cache.h"
|
@@ -3297,15 +3299,118 @@ int uname(struct utsname *buf)
|
3297 | 3299 | return 0;
|
3298 | 3300 | }
|
3299 | 3301 |
|
| 3302 | +/* |
| 3303 | + * Verify that the file in question is owned by an administrator or system |
| 3304 | + * account, or at least by the current user. |
| 3305 | + * |
| 3306 | + * This function returns 1 if successful, 0 if the file is not owned by any of |
| 3307 | + * these, or -1 on error. |
| 3308 | + */ |
| 3309 | +static int validate_system_file_ownership(const char *path) |
| 3310 | +{ |
| 3311 | + WCHAR wpath[MAX_LONG_PATH]; |
| 3312 | + PSID owner_sid = NULL; |
| 3313 | + PSECURITY_DESCRIPTOR descriptor = NULL; |
| 3314 | + HANDLE token; |
| 3315 | + TOKEN_USER* info; |
| 3316 | + DWORD err, len; |
| 3317 | + int ret; |
| 3318 | + |
| 3319 | + if (xutftowcs_long_path(wpath, path) < 0) |
| 3320 | + return -1; |
| 3321 | + |
| 3322 | + err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT, |
| 3323 | + OWNER_SECURITY_INFORMATION | |
| 3324 | + DACL_SECURITY_INFORMATION, |
| 3325 | + &owner_sid, NULL, NULL, NULL, &descriptor); |
| 3326 | + |
| 3327 | + /* if the file does not exist, it does not have a valid owner */ |
| 3328 | + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { |
| 3329 | + ret = 0; |
| 3330 | + owner_sid = NULL; |
| 3331 | + goto finish_validation; |
| 3332 | + } |
| 3333 | + |
| 3334 | + if (err != ERROR_SUCCESS) { |
| 3335 | + ret = error(_("failed to validate '%s' (%ld)"), path, err); |
| 3336 | + owner_sid = NULL; |
| 3337 | + goto finish_validation; |
| 3338 | + } |
| 3339 | + |
| 3340 | + if (!IsValidSid(owner_sid)) { |
| 3341 | + ret = error(_("invalid owner: '%s'"), path); |
| 3342 | + goto finish_validation; |
| 3343 | + } |
| 3344 | + |
| 3345 | + if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || |
| 3346 | + IsWellKnownSid(owner_sid, WinLocalSystemSid)) { |
| 3347 | + ret = 1; |
| 3348 | + goto finish_validation; |
| 3349 | + } |
| 3350 | + |
| 3351 | + /* Obtain current user's SID */ |
| 3352 | + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) && |
| 3353 | + !GetTokenInformation(token, TokenUser, NULL, 0, &len)) { |
| 3354 | + info = xmalloc((size_t)len); |
| 3355 | + if (!GetTokenInformation(token, TokenUser, info, len, &len)) |
| 3356 | + FREE_AND_NULL(info); |
| 3357 | + } |
| 3358 | + |
| 3359 | + if (!info) |
| 3360 | + ret = 0; |
| 3361 | + else { |
| 3362 | + ret = EqualSid(owner_sid, info->User.Sid) ? 1 : 0; |
| 3363 | + free(info); |
| 3364 | + } |
| 3365 | + |
| 3366 | +finish_validation: |
| 3367 | + if (!ret && owner_sid) { |
| 3368 | +#define MAX_NAME_OR_DOMAIN 256 |
| 3369 | + wchar_t owner_name[MAX_NAME_OR_DOMAIN]; |
| 3370 | + wchar_t owner_domain[MAX_NAME_OR_DOMAIN]; |
| 3371 | + wchar_t *p = NULL; |
| 3372 | + DWORD size = MAX_NAME_OR_DOMAIN; |
| 3373 | + SID_NAME_USE type; |
| 3374 | + char name[3 * MAX_NAME_OR_DOMAIN + 1]; |
| 3375 | + |
| 3376 | + if (!LookupAccountSidW(NULL, owner_sid, owner_name, &size, |
| 3377 | + owner_domain, &size, &type) || |
| 3378 | + xwcstoutf(name, owner_name, ARRAY_SIZE(name)) < 0) { |
| 3379 | + if (!ConvertSidToStringSidW(owner_sid, &p)) |
| 3380 | + strlcpy(name, "(unknown)", ARRAY_SIZE(name)); |
| 3381 | + else { |
| 3382 | + if (xwcstoutf(name, p, ARRAY_SIZE(name)) < 0) |
| 3383 | + strlcpy(name, "(some user)", |
| 3384 | + ARRAY_SIZE(name)); |
| 3385 | + LocalFree(p); |
| 3386 | + } |
| 3387 | + } |
| 3388 | + |
| 3389 | + warning(_("'%s' has a dubious owner: '%s'.\n" |
| 3390 | + "For security reasons, it is therefore ignored.\n" |
| 3391 | + "To fix this, please transfer ownership to an " |
| 3392 | + "admininstrator."), |
| 3393 | + path, name); |
| 3394 | + } |
| 3395 | + |
| 3396 | + if (descriptor) |
| 3397 | + LocalFree(descriptor); |
| 3398 | + |
| 3399 | + return ret; |
| 3400 | +} |
| 3401 | + |
3300 | 3402 | const char *program_data_config(void)
|
3301 | 3403 | {
|
3302 | 3404 | static struct strbuf path = STRBUF_INIT;
|
3303 | 3405 | static unsigned initialized;
|
3304 | 3406 |
|
3305 | 3407 | if (!initialized) {
|
3306 | 3408 | const char *env = mingw_getenv("PROGRAMDATA");
|
3307 |
| - if (env) |
| 3409 | + if (env) { |
3308 | 3410 | strbuf_addf(&path, "%s/Git/config", env);
|
| 3411 | + if (validate_system_file_ownership(path.buf) != 1) |
| 3412 | + strbuf_setlen(&path, 0); |
| 3413 | + } |
3309 | 3414 | initialized = 1;
|
3310 | 3415 | }
|
3311 | 3416 | return *path.buf ? path.buf : NULL;
|
|
0 commit comments