Create `path` with an explicit private security descriptor: owner stamped * to the token user and a protected, inheritable, user-only DACL. A plain * _mkdir takes the token's DEFAULT owner and the parent's inheritable DACL; * under an Administrators-default-owner policy (standard on Windows Server * and GitHub's elevated runners) the directory is then born owned by * BUILTIN\Administrators wi
| 70 | * back to plain _mkdir so degraded environments (Wine) keep working — |
| 71 | * downstream validation still gates security there. */ |
| 72 | static bool win_mkdtemp_private_create(const char *path) { |
| 73 | bool created = false; |
| 74 | HANDLE token = NULL; |
| 75 | TOKEN_USER *user = NULL; |
| 76 | PACL acl = NULL; |
| 77 | DWORD needed = 0; |
| 78 | wchar_t *wide = cbm_path_to_wide(path); |
| 79 | if (wide && OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) && |
| 80 | !GetTokenInformation(token, TokenUser, NULL, 0, &needed) && |
| 81 | GetLastError() == ERROR_INSUFFICIENT_BUFFER && (user = malloc(needed)) != NULL && |
| 82 | GetTokenInformation(token, TokenUser, user, needed, &needed) && user->User.Sid && |
| 83 | IsValidSid(user->User.Sid)) { |
| 84 | EXPLICIT_ACCESSW access; |
| 85 | memset(&access, 0, sizeof(access)); |
| 86 | access.grfAccessPermissions = GENERIC_ALL; |
| 87 | access.grfAccessMode = SET_ACCESS; |
| 88 | access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; |
| 89 | access.Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 90 | access.Trustee.TrusteeType = TRUSTEE_IS_USER; |
| 91 | access.Trustee.ptstrName = (LPWSTR)user->User.Sid; |
| 92 | SECURITY_DESCRIPTOR descriptor; |
| 93 | if (SetEntriesInAclW(1, &access, NULL, &acl) == ERROR_SUCCESS && |
| 94 | InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION) && |
| 95 | SetSecurityDescriptorDacl(&descriptor, TRUE, acl, FALSE) && |
| 96 | SetSecurityDescriptorOwner(&descriptor, user->User.Sid, FALSE) && |
| 97 | SetSecurityDescriptorControl(&descriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { |
| 98 | SECURITY_ATTRIBUTES attributes; |
| 99 | attributes.nLength = sizeof(attributes); |
| 100 | attributes.lpSecurityDescriptor = &descriptor; |
| 101 | attributes.bInheritHandle = FALSE; |
| 102 | created = CreateDirectoryW(wide, &attributes) != 0; |
| 103 | } |
| 104 | } |
| 105 | if (acl) { |
| 106 | (void)LocalFree(acl); |
| 107 | } |
| 108 | free(user); |
| 109 | if (token) { |
| 110 | (void)CloseHandle(token); |
| 111 | } |
| 112 | free(wide); |
| 113 | return created; |
| 114 | } |
| 115 | |
| 116 | char *cbm_mkdtemp(char *tmpl) { |
| 117 | /* Build path in static buffer, then copy back to caller. |
no test coverage detected