24
24
#include "pycore_ceval.h" // _PyEval_ReInitThreads()
25
25
#include "pycore_import.h" // _PyImport_ReInitLock()
26
26
#include "pycore_pystate.h" // _PyInterpreterState_GET()
27
+
28
+ #ifdef MS_WINDOWS
29
+ # include <aclapi.h> // SetEntriesInAcl
30
+ # include <sddl.h> // SDDL_REVISION_1
31
+ #endif
32
+
27
33
#include "structmember.h" // PyMemberDef
28
34
#ifndef MS_WINDOWS
29
35
# include "posixmodule.h"
@@ -4426,6 +4432,146 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
4426
4432
#endif /* MS_WINDOWS */
4427
4433
4428
4434
4435
+ #ifdef MS_WINDOWS
4436
+
4437
+ /* We centralise SECURITY_ATTRIBUTE initialization based around
4438
+ templates that will probably mostly match common POSIX mode settings.
4439
+ The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as
4440
+ a constructed SECURITY_ATTRIBUTE structure typically refers to memory
4441
+ that has to be alive while it's being used.
4442
+
4443
+ Typical use will look like:
4444
+ SECURITY_ATTRIBUTES *pSecAttr = NULL;
4445
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
4446
+ int error, error2;
4447
+
4448
+ Py_BEGIN_ALLOW_THREADS
4449
+ switch (mode) {
4450
+ case 0x1C0: // 0o700
4451
+ error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
4452
+ break;
4453
+ ...
4454
+ default:
4455
+ error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
4456
+ break;
4457
+ }
4458
+
4459
+ if (!error) {
4460
+ // do operation, passing pSecAttr
4461
+ }
4462
+
4463
+ // Unconditionally clear secAttrData.
4464
+ error2 = clearSecurityAttributes(&pSecAttr, &secAttrData);
4465
+ if (!error) {
4466
+ error = error2;
4467
+ }
4468
+ Py_END_ALLOW_THREADS
4469
+
4470
+ if (error) {
4471
+ PyErr_SetFromWindowsErr(error);
4472
+ return NULL;
4473
+ }
4474
+ */
4475
+
4476
+ struct _Py_SECURITY_ATTRIBUTE_DATA {
4477
+ SECURITY_ATTRIBUTES securityAttributes ;
4478
+ PACL acl ;
4479
+ SECURITY_DESCRIPTOR sd ;
4480
+ EXPLICIT_ACCESS_W ea [4 ];
4481
+ char sid [64 ];
4482
+ };
4483
+
4484
+ static int
4485
+ initializeDefaultSecurityAttributes (
4486
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4487
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4488
+ ) {
4489
+ assert (securityAttributes );
4490
+ assert (data );
4491
+ * securityAttributes = NULL ;
4492
+ memset (data , 0 , sizeof (* data ));
4493
+ return 0 ;
4494
+ }
4495
+
4496
+ static int
4497
+ initializeMkdir700SecurityAttributes (
4498
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4499
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4500
+ ) {
4501
+ assert (securityAttributes );
4502
+ assert (data );
4503
+ * securityAttributes = NULL ;
4504
+ memset (data , 0 , sizeof (* data ));
4505
+
4506
+ if (!InitializeSecurityDescriptor (& data -> sd , SECURITY_DESCRIPTOR_REVISION )
4507
+ || !SetSecurityDescriptorGroup (& data -> sd , NULL , TRUE)) {
4508
+ return GetLastError ();
4509
+ }
4510
+
4511
+ int use_alias = 0 ;
4512
+ DWORD cbSid = sizeof (data -> sid );
4513
+ if (!CreateWellKnownSid (WinCreatorOwnerRightsSid , NULL , (PSID )data -> sid , & cbSid )) {
4514
+ use_alias = 1 ;
4515
+ }
4516
+
4517
+ data -> securityAttributes .nLength = sizeof (SECURITY_ATTRIBUTES );
4518
+ data -> ea [0 ].grfAccessPermissions = GENERIC_ALL ;
4519
+ data -> ea [0 ].grfAccessMode = SET_ACCESS ;
4520
+ data -> ea [0 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4521
+ if (use_alias ) {
4522
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4523
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4524
+ data -> ea [0 ].Trustee .ptstrName = L"CURRENT_USER" ;
4525
+ } else {
4526
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_SID ;
4527
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP ;
4528
+ data -> ea [0 ].Trustee .ptstrName = (LPWCH )(SID * )data -> sid ;
4529
+ }
4530
+
4531
+ data -> ea [1 ].grfAccessPermissions = GENERIC_ALL ;
4532
+ data -> ea [1 ].grfAccessMode = SET_ACCESS ;
4533
+ data -> ea [1 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4534
+ data -> ea [1 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4535
+ data -> ea [1 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4536
+ data -> ea [1 ].Trustee .ptstrName = L"SYSTEM" ;
4537
+
4538
+ data -> ea [2 ].grfAccessPermissions = GENERIC_ALL ;
4539
+ data -> ea [2 ].grfAccessMode = SET_ACCESS ;
4540
+ data -> ea [2 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4541
+ data -> ea [2 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4542
+ data -> ea [2 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4543
+ data -> ea [2 ].Trustee .ptstrName = L"ADMINISTRATORS" ;
4544
+
4545
+ int r = SetEntriesInAclW (3 , data -> ea , NULL , & data -> acl );
4546
+ if (r ) {
4547
+ return r ;
4548
+ }
4549
+ if (!SetSecurityDescriptorDacl (& data -> sd , TRUE, data -> acl , FALSE)) {
4550
+ return GetLastError ();
4551
+ }
4552
+ data -> securityAttributes .lpSecurityDescriptor = & data -> sd ;
4553
+ * securityAttributes = & data -> securityAttributes ;
4554
+ return 0 ;
4555
+ }
4556
+
4557
+ static int
4558
+ clearSecurityAttributes (
4559
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4560
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4561
+ ) {
4562
+ assert (securityAttributes );
4563
+ assert (data );
4564
+ * securityAttributes = NULL ;
4565
+ if (data -> acl ) {
4566
+ if (LocalFree ((void * )data -> acl )) {
4567
+ return GetLastError ();
4568
+ }
4569
+ }
4570
+ return 0 ;
4571
+ }
4572
+
4573
+ #endif
4574
+
4429
4575
/*[clinic input]
4430
4576
os.mkdir
4431
4577
@@ -4454,6 +4600,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4454
4600
/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
4455
4601
{
4456
4602
int result ;
4603
+ #ifdef MS_WINDOWS
4604
+ int error = 0 ;
4605
+ int pathError = 0 ;
4606
+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4607
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData ;
4608
+ #endif
4457
4609
#ifdef HAVE_MKDIRAT
4458
4610
int mkdirat_unavailable = 0 ;
4459
4611
#endif
@@ -4465,11 +4617,30 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4465
4617
4466
4618
#ifdef MS_WINDOWS
4467
4619
Py_BEGIN_ALLOW_THREADS
4468
- result = CreateDirectoryW (path -> wide , NULL );
4620
+ switch (mode ) {
4621
+ case 0x1C0 : // 0o700
4622
+ error = initializeMkdir700SecurityAttributes (& pSecAttr , & secAttrData );
4623
+ break ;
4624
+ default :
4625
+ error = initializeDefaultSecurityAttributes (& pSecAttr , & secAttrData );
4626
+ break ;
4627
+ }
4628
+ if (!error ) {
4629
+ result = CreateDirectoryW (path -> wide , pSecAttr );
4630
+ error = clearSecurityAttributes (& pSecAttr , & secAttrData );
4631
+ } else {
4632
+ // Ignore error from "clear" - we have a more interesting one already
4633
+ clearSecurityAttributes (& pSecAttr , & secAttrData );
4634
+ }
4469
4635
Py_END_ALLOW_THREADS
4470
4636
4471
- if (!result )
4637
+ if (error ) {
4638
+ PyErr_SetFromWindowsErr (error );
4639
+ return NULL ;
4640
+ }
4641
+ if (!result ) {
4472
4642
return path_error (path );
4643
+ }
4473
4644
#else
4474
4645
Py_BEGIN_ALLOW_THREADS
4475
4646
#if HAVE_MKDIRAT
0 commit comments