aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-01-16 11:03:30 +0000
committerRon Yorston <rmy@pobox.com>2023-01-16 11:03:30 +0000
commit88965fe20a26e17247e6ffc10692fe202d77f1fa (patch)
tree16109de1bf8fb14d04c3c5f4176ec20c77ea7f6d
parent857b0732b9268c049e94bb3220fbb078f662ab02 (diff)
downloadbusybox-w32-88965fe20a26e17247e6ffc10692fe202d77f1fa.tar.gz
busybox-w32-88965fe20a26e17247e6ffc10692fe202d77f1fa.tar.bz2
busybox-w32-88965fe20a26e17247e6ffc10692fe202d77f1fa.zip
win32: use ACL check to clarify write permission
On Microsoft Windows a user's home directory doesn't belong to them: it actually belongs to the 'system' user. stat(2) was only using ownership to determine write permissions, so it seemed that the user was unable to write to their own home directory. Use a call to AccessCheck() to determine if files can be accessed due to an entry in their ACL. User home directories and a few other files (e.g. C:/Users/Public) now have the correct write permission. This feature is enabled by FEATURE_EXTRA_FILE_DATA. Costs 220-256 bytes. (GitHub issue #280)
-rw-r--r--win32/mingw.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/win32/mingw.c b/win32/mingw.c
index a2a736d52..bfc1531fb 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -494,11 +494,13 @@ static int has_exec_format(const char *name)
494} 494}
495 495
496#if ENABLE_FEATURE_EXTRA_FILE_DATA 496#if ENABLE_FEATURE_EXTRA_FILE_DATA
497static uid_t file_owner(HANDLE fh) 497static uid_t file_owner(HANDLE fh, struct mingw_stat *buf)
498{ 498{
499 PSID pSidOwner; 499 PSID pSidOwner;
500 PACL pDACL;
500 PSECURITY_DESCRIPTOR pSD; 501 PSECURITY_DESCRIPTOR pSD;
501 static PTOKEN_USER user = NULL; 502 static PTOKEN_USER user = NULL;
503 static HANDLE impersonate = INVALID_HANDLE_VALUE;
502 static int initialised = 0; 504 static int initialised = 0;
503 uid_t uid = 0; 505 uid_t uid = 0;
504 DWORD *ptr; 506 DWORD *ptr;
@@ -519,13 +521,16 @@ static uid_t file_owner(HANDLE fh)
519 DWORD ret = 0; 521 DWORD ret = 0;
520 522
521 initialised = 1; 523 initialised = 1;
522 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { 524 if (OpenProcessToken(GetCurrentProcess(),
525 TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE |
526 STANDARD_RIGHTS_READ, &token)) {
523 GetTokenInformation(token, TokenUser, NULL, 0, &ret); 527 GetTokenInformation(token, TokenUser, NULL, 0, &ret);
524 if (ret <= 0 || (user=malloc(ret)) == NULL || 528 if (ret <= 0 || (user=malloc(ret)) == NULL ||
525 !GetTokenInformation(token, TokenUser, user, ret, &ret)) { 529 !GetTokenInformation(token, TokenUser, user, ret, &ret)) {
526 free(user); 530 free(user);
527 user = NULL; 531 user = NULL;
528 } 532 }
533 DuplicateToken(token, SecurityImpersonation, &impersonate);
529 CloseHandle(token); 534 CloseHandle(token);
530 } 535 }
531 } 536 }
@@ -534,8 +539,10 @@ static uid_t file_owner(HANDLE fh)
534 return DEFAULT_UID; 539 return DEFAULT_UID;
535 540
536 /* get SID of file's owner */ 541 /* get SID of file's owner */
537 if (GetSecurityInfo(fh, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, 542 if (GetSecurityInfo(fh, SE_FILE_OBJECT,
538 &pSidOwner, NULL, NULL, NULL, &pSD) != ERROR_SUCCESS) 543 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
544 DACL_SECURITY_INFORMATION,
545 &pSidOwner, NULL, &pDACL, NULL, &pSD) != ERROR_SUCCESS)
539 return 0; 546 return 0;
540 547
541 if (EqualSid(pSidOwner, user->User.Sid)) { 548 if (EqualSid(pSidOwner, user->User.Sid)) {
@@ -548,33 +555,28 @@ static uid_t file_owner(HANDLE fh)
548 if (ptr[6] >= 500 && ptr[6] < DEFAULT_UID) 555 if (ptr[6] >= 500 && ptr[6] < DEFAULT_UID)
549 uid = (uid_t)ptr[6]; 556 uid = (uid_t)ptr[6];
550 } 557 }
551 LocalFree(pSD);
552 return uid;
553 558
554#if 0 559 if (uid != DEFAULT_UID && impersonate != INVALID_HANDLE_VALUE) {
555 /* this is how it would be done properly using the API */ 560 static GENERIC_MAPPING mapping = {
556 { 561 FILE_GENERIC_READ, FILE_GENERIC_WRITE,
557 PSID_IDENTIFIER_AUTHORITY auth; 562 FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS
558 unsigned char *count;
559 PDWORD subauth;
560 unsigned char nt_auth[] = {
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x05
562 }; 563 };
563 564 PRIVILEGE_SET privileges;
564 if (IsValidSid(pSidOwner) ) { 565 DWORD grantedAccess;
565 auth = GetSidIdentifierAuthority(pSidOwner); 566 DWORD privilegesLength = sizeof(privileges);
566 count = GetSidSubAuthorityCount(pSidOwner); 567 DWORD genericAccessRights = MAXIMUM_ALLOWED;
567 subauth = GetSidSubAuthority(pSidOwner, 0); 568 BOOL result;
568 if (memcmp(auth, nt_auth, sizeof(nt_auth)) == 0 && 569
569 *count == 5 && *subauth == 21) { 570 if (AccessCheck(pSD, impersonate, genericAccessRights,
570 subauth = GetSidSubAuthority(pSidOwner, 4); 571 &mapping, &privileges, &privilegesLength,
571 if (*subauth >= 500 && *subauth < DEFAULT_UID) 572 &grantedAccess, &result)) {
572 uid = (uid_t)*subauth; 573 if (result && (grantedAccess & 0x1200af) == 0x1200af) {
574 buf->st_mode |= (buf->st_mode & S_IRWXU) >> 6;
573 } 575 }
574 } 576 }
575 return uid;
576 } 577 }
577#endif 578 LocalFree(pSD);
579 return uid;
578} 580}
579#endif 581#endif
580 582
@@ -711,7 +713,8 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
711 count_subdirs(file_name) : 713 count_subdirs(file_name) :
712 hdata.nNumberOfLinks; 714 hdata.nNumberOfLinks;
713 } 715 }
714 buf->st_uid = buf->st_gid = file_owner(fh); 716
717 buf->st_uid = buf->st_gid = file_owner(fh, buf);
715 CloseHandle(fh); 718 CloseHandle(fh);
716 } 719 }
717 else { 720 else {