|
2 | 2 | #include "win32.h"
|
3 | 3 | #include <conio.h>
|
4 | 4 | #include <wchar.h>
|
| 5 | +#include <aclapi.h> |
| 6 | +#include <sddl.h> |
5 | 7 | #include "../strbuf.h"
|
6 | 8 | #include "../run-command.h"
|
7 | 9 | #include "../cache.h"
|
@@ -2450,3 +2452,120 @@ int uname(struct utsname *buf)
|
2450 | 2452 | "%u", (v >> 16) & 0x7fff);
|
2451 | 2453 | return 0;
|
2452 | 2454 | }
|
| 2455 | + |
| 2456 | +/* |
| 2457 | + * Verify that the file in question is owned by an administrator or system |
| 2458 | + * account, or at least by the current user. |
| 2459 | + * |
| 2460 | + * This function returns 1 if successful, 0 if the file is not owned by any of |
| 2461 | + * these, or -1 on error. |
| 2462 | + */ |
| 2463 | +static int validate_system_file_ownership(const char *path) |
| 2464 | +{ |
| 2465 | + WCHAR wpath[MAX_PATH]; |
| 2466 | + PSID owner_sid = NULL; |
| 2467 | + PSECURITY_DESCRIPTOR descriptor = NULL; |
| 2468 | + HANDLE token; |
| 2469 | + TOKEN_USER* info = NULL; |
| 2470 | + DWORD err, len; |
| 2471 | + int ret; |
| 2472 | + |
| 2473 | + if (xutftowcs_path(wpath, path) < 0) |
| 2474 | + return -1; |
| 2475 | + |
| 2476 | + err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT, |
| 2477 | + OWNER_SECURITY_INFORMATION | |
| 2478 | + DACL_SECURITY_INFORMATION, |
| 2479 | + &owner_sid, NULL, NULL, NULL, &descriptor); |
| 2480 | + |
| 2481 | + /* if the file does not exist, it does not have a valid owner */ |
| 2482 | + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { |
| 2483 | + ret = 0; |
| 2484 | + owner_sid = NULL; |
| 2485 | + goto finish_validation; |
| 2486 | + } |
| 2487 | + |
| 2488 | + if (err != ERROR_SUCCESS) { |
| 2489 | + ret = error(_("failed to validate '%s' (%ld)"), path, err); |
| 2490 | + owner_sid = NULL; |
| 2491 | + goto finish_validation; |
| 2492 | + } |
| 2493 | + |
| 2494 | + if (!IsValidSid(owner_sid)) { |
| 2495 | + ret = error(_("invalid owner: '%s'"), path); |
| 2496 | + goto finish_validation; |
| 2497 | + } |
| 2498 | + |
| 2499 | + if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || |
| 2500 | + IsWellKnownSid(owner_sid, WinLocalSystemSid)) { |
| 2501 | + ret = 1; |
| 2502 | + goto finish_validation; |
| 2503 | + } |
| 2504 | + |
| 2505 | + /* Obtain current user's SID */ |
| 2506 | + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) && |
| 2507 | + !GetTokenInformation(token, TokenUser, NULL, 0, &len)) { |
| 2508 | + info = xmalloc((size_t)len); |
| 2509 | + if (!GetTokenInformation(token, TokenUser, info, len, &len)) |
| 2510 | + FREE_AND_NULL(info); |
| 2511 | + } |
| 2512 | + |
| 2513 | + if (!info) |
| 2514 | + ret = 0; |
| 2515 | + else { |
| 2516 | + ret = EqualSid(owner_sid, info->User.Sid) ? 1 : 0; |
| 2517 | + free(info); |
| 2518 | + } |
| 2519 | + |
| 2520 | +finish_validation: |
| 2521 | + if (!ret && owner_sid) { |
| 2522 | +#define MAX_NAME_OR_DOMAIN 256 |
| 2523 | + wchar_t owner_name[MAX_NAME_OR_DOMAIN]; |
| 2524 | + wchar_t owner_domain[MAX_NAME_OR_DOMAIN]; |
| 2525 | + wchar_t *p = NULL; |
| 2526 | + DWORD size = MAX_NAME_OR_DOMAIN; |
| 2527 | + SID_NAME_USE type; |
| 2528 | + char name[3 * MAX_NAME_OR_DOMAIN + 1]; |
| 2529 | + |
| 2530 | + if (!LookupAccountSidW(NULL, owner_sid, owner_name, &size, |
| 2531 | + owner_domain, &size, &type) || |
| 2532 | + xwcstoutf(name, owner_name, ARRAY_SIZE(name)) < 0) { |
| 2533 | + if (!ConvertSidToStringSidW(owner_sid, &p)) |
| 2534 | + strlcpy(name, "(unknown)", ARRAY_SIZE(name)); |
| 2535 | + else { |
| 2536 | + if (xwcstoutf(name, p, ARRAY_SIZE(name)) < 0) |
| 2537 | + strlcpy(name, "(some user)", |
| 2538 | + ARRAY_SIZE(name)); |
| 2539 | + LocalFree(p); |
| 2540 | + } |
| 2541 | + } |
| 2542 | + |
| 2543 | + warning(_("'%s' has a dubious owner: '%s'.\n" |
| 2544 | + "For security reasons, it is therefore ignored.\n" |
| 2545 | + "To fix this, please transfer ownership to an " |
| 2546 | + "admininstrator."), |
| 2547 | + path, name); |
| 2548 | + } |
| 2549 | + |
| 2550 | + if (descriptor) |
| 2551 | + LocalFree(descriptor); |
| 2552 | + |
| 2553 | + return ret; |
| 2554 | +} |
| 2555 | + |
| 2556 | +const char *program_data_config(void) |
| 2557 | +{ |
| 2558 | + static struct strbuf path = STRBUF_INIT; |
| 2559 | + static unsigned initialized; |
| 2560 | + |
| 2561 | + if (!initialized) { |
| 2562 | + const char *env = mingw_getenv("PROGRAMDATA"); |
| 2563 | + if (env) { |
| 2564 | + strbuf_addf(&path, "%s/Git/config", env); |
| 2565 | + if (validate_system_file_ownership(path.buf) != 1) |
| 2566 | + strbuf_setlen(&path, 0); |
| 2567 | + } |
| 2568 | + initialized = 1; |
| 2569 | + } |
| 2570 | + return *path.buf ? path.buf : NULL; |
| 2571 | +} |
0 commit comments