Skip to content

Commit 8af84b5

Browse files
authored
gh-118773: Use language-invariant SDDL string instead of aliases for ACLs. (GH-118800)
1 parent c30d8e5 commit 8af84b5

File tree

2 files changed

+24
-154
lines changed

2 files changed

+24
-154
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixes creation of ACLs in :func:`os.mkdir` on Windows to work correctly on
2+
non-English machines.

Modules/posixmodule.c

Lines changed: 22 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -5541,146 +5541,6 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
55415541
return result;
55425542
}
55435543

5544-
#ifdef MS_WINDOWS
5545-
5546-
/* We centralise SECURITY_ATTRIBUTE initialization based around
5547-
templates that will probably mostly match common POSIX mode settings.
5548-
The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as
5549-
a constructed SECURITY_ATTRIBUTE structure typically refers to memory
5550-
that has to be alive while it's being used.
5551-
5552-
Typical use will look like:
5553-
SECURITY_ATTRIBUTES *pSecAttr = NULL;
5554-
struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
5555-
int error, error2;
5556-
5557-
Py_BEGIN_ALLOW_THREADS
5558-
switch (mode) {
5559-
case 0x1C0: // 0o700
5560-
error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
5561-
break;
5562-
...
5563-
default:
5564-
error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
5565-
break;
5566-
}
5567-
5568-
if (!error) {
5569-
// do operation, passing pSecAttr
5570-
}
5571-
5572-
// Unconditionally clear secAttrData.
5573-
error2 = clearSecurityAttributes(&pSecAttr, &secAttrData);
5574-
if (!error) {
5575-
error = error2;
5576-
}
5577-
Py_END_ALLOW_THREADS
5578-
5579-
if (error) {
5580-
PyErr_SetFromWindowsErr(error);
5581-
return NULL;
5582-
}
5583-
*/
5584-
5585-
struct _Py_SECURITY_ATTRIBUTE_DATA {
5586-
SECURITY_ATTRIBUTES securityAttributes;
5587-
PACL acl;
5588-
SECURITY_DESCRIPTOR sd;
5589-
EXPLICIT_ACCESS_W ea[4];
5590-
char sid[64];
5591-
};
5592-
5593-
static int
5594-
initializeDefaultSecurityAttributes(
5595-
PSECURITY_ATTRIBUTES *securityAttributes,
5596-
struct _Py_SECURITY_ATTRIBUTE_DATA *data
5597-
) {
5598-
assert(securityAttributes);
5599-
assert(data);
5600-
*securityAttributes = NULL;
5601-
memset(data, 0, sizeof(*data));
5602-
return 0;
5603-
}
5604-
5605-
static int
5606-
initializeMkdir700SecurityAttributes(
5607-
PSECURITY_ATTRIBUTES *securityAttributes,
5608-
struct _Py_SECURITY_ATTRIBUTE_DATA *data
5609-
) {
5610-
assert(securityAttributes);
5611-
assert(data);
5612-
*securityAttributes = NULL;
5613-
memset(data, 0, sizeof(*data));
5614-
5615-
if (!InitializeSecurityDescriptor(&data->sd, SECURITY_DESCRIPTOR_REVISION)
5616-
|| !SetSecurityDescriptorGroup(&data->sd, NULL, TRUE)) {
5617-
return GetLastError();
5618-
}
5619-
5620-
int use_alias = 0;
5621-
DWORD cbSid = sizeof(data->sid);
5622-
if (!CreateWellKnownSid(WinCreatorOwnerRightsSid, NULL, (PSID)data->sid, &cbSid)) {
5623-
use_alias = 1;
5624-
}
5625-
5626-
data->securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
5627-
data->ea[0].grfAccessPermissions = GENERIC_ALL;
5628-
data->ea[0].grfAccessMode = SET_ACCESS;
5629-
data->ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
5630-
if (use_alias) {
5631-
data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
5632-
data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
5633-
data->ea[0].Trustee.ptstrName = L"CURRENT_USER";
5634-
} else {
5635-
data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
5636-
data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
5637-
data->ea[0].Trustee.ptstrName = (LPWCH)(SID*)data->sid;
5638-
}
5639-
5640-
data->ea[1].grfAccessPermissions = GENERIC_ALL;
5641-
data->ea[1].grfAccessMode = SET_ACCESS;
5642-
data->ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
5643-
data->ea[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
5644-
data->ea[1].Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
5645-
data->ea[1].Trustee.ptstrName = L"SYSTEM";
5646-
5647-
data->ea[2].grfAccessPermissions = GENERIC_ALL;
5648-
data->ea[2].grfAccessMode = SET_ACCESS;
5649-
data->ea[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
5650-
data->ea[2].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
5651-
data->ea[2].Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
5652-
data->ea[2].Trustee.ptstrName = L"ADMINISTRATORS";
5653-
5654-
int r = SetEntriesInAclW(3, data->ea, NULL, &data->acl);
5655-
if (r) {
5656-
return r;
5657-
}
5658-
if (!SetSecurityDescriptorDacl(&data->sd, TRUE, data->acl, FALSE)) {
5659-
return GetLastError();
5660-
}
5661-
data->securityAttributes.lpSecurityDescriptor = &data->sd;
5662-
*securityAttributes = &data->securityAttributes;
5663-
return 0;
5664-
}
5665-
5666-
static int
5667-
clearSecurityAttributes(
5668-
PSECURITY_ATTRIBUTES *securityAttributes,
5669-
struct _Py_SECURITY_ATTRIBUTE_DATA *data
5670-
) {
5671-
assert(securityAttributes);
5672-
assert(data);
5673-
*securityAttributes = NULL;
5674-
if (data->acl) {
5675-
if (LocalFree((void *)data->acl)) {
5676-
return GetLastError();
5677-
}
5678-
}
5679-
return 0;
5680-
}
5681-
5682-
#endif
5683-
56845544
/*[clinic input]
56855545
os.mkdir
56865546
@@ -5713,8 +5573,8 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
57135573
#ifdef MS_WINDOWS
57145574
int error = 0;
57155575
int pathError = 0;
5576+
SECURITY_ATTRIBUTES secAttr = { sizeof(secAttr) };
57165577
SECURITY_ATTRIBUTES *pSecAttr = NULL;
5717-
struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
57185578
#endif
57195579
#ifdef HAVE_MKDIRAT
57205580
int mkdirat_unavailable = 0;
@@ -5727,26 +5587,34 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
57275587

57285588
#ifdef MS_WINDOWS
57295589
Py_BEGIN_ALLOW_THREADS
5730-
switch (mode) {
5731-
case 0x1C0: // 0o700
5732-
error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
5733-
break;
5734-
default:
5735-
error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
5736-
break;
5590+
if (mode == 0700 /* 0o700 */) {
5591+
ULONG sdSize;
5592+
pSecAttr = &secAttr;
5593+
// Set a discreationary ACL (D) that is protected (P) and includes
5594+
// inheritable (OICI) entries that allow (A) full control (FA) to
5595+
// SYSTEM (SY), Administrators (BA), and the owner (OW).
5596+
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
5597+
L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)",
5598+
SDDL_REVISION_1,
5599+
&secAttr.lpSecurityDescriptor,
5600+
&sdSize
5601+
)) {
5602+
error = GetLastError();
5603+
}
57375604
}
57385605
if (!error) {
57395606
result = CreateDirectoryW(path->wide, pSecAttr);
5740-
error = clearSecurityAttributes(&pSecAttr, &secAttrData);
5741-
} else {
5742-
// Ignore error from "clear" - we have a more interesting one already
5743-
clearSecurityAttributes(&pSecAttr, &secAttrData);
5607+
if (secAttr.lpSecurityDescriptor &&
5608+
// uncommonly, LocalFree returns non-zero on error, but still uses
5609+
// GetLastError() to see what the error code is
5610+
LocalFree(secAttr.lpSecurityDescriptor)) {
5611+
error = GetLastError();
5612+
}
57445613
}
57455614
Py_END_ALLOW_THREADS
57465615

57475616
if (error) {
5748-
PyErr_SetFromWindowsErr(error);
5749-
return NULL;
5617+
return PyErr_SetFromWindowsErr(error);
57505618
}
57515619
if (!result) {
57525620
return path_error(path);

0 commit comments

Comments
 (0)