34
34
#include "pycore_pystate.h" // _PyInterpreterState_GET()
35
35
#include "pycore_signal.h" // Py_NSIG
36
36
37
+ #ifdef MS_WINDOWS
38
+ # include <aclapi.h> // SetEntriesInAcl
39
+ # include <sddl.h> // SDDL_REVISION_1
40
+ #endif
41
+
37
42
#include "structmember.h" // PyMemberDef
38
43
#ifndef MS_WINDOWS
39
44
# include "posixmodule.h"
@@ -4582,6 +4587,146 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
4582
4587
return result ;
4583
4588
}
4584
4589
4590
+ #ifdef MS_WINDOWS
4591
+
4592
+ /* We centralise SECURITY_ATTRIBUTE initialization based around
4593
+ templates that will probably mostly match common POSIX mode settings.
4594
+ The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as
4595
+ a constructed SECURITY_ATTRIBUTE structure typically refers to memory
4596
+ that has to be alive while it's being used.
4597
+
4598
+ Typical use will look like:
4599
+ SECURITY_ATTRIBUTES *pSecAttr = NULL;
4600
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
4601
+ int error, error2;
4602
+
4603
+ Py_BEGIN_ALLOW_THREADS
4604
+ switch (mode) {
4605
+ case 0x1C0: // 0o700
4606
+ error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
4607
+ break;
4608
+ ...
4609
+ default:
4610
+ error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
4611
+ break;
4612
+ }
4613
+
4614
+ if (!error) {
4615
+ // do operation, passing pSecAttr
4616
+ }
4617
+
4618
+ // Unconditionally clear secAttrData.
4619
+ error2 = clearSecurityAttributes(&pSecAttr, &secAttrData);
4620
+ if (!error) {
4621
+ error = error2;
4622
+ }
4623
+ Py_END_ALLOW_THREADS
4624
+
4625
+ if (error) {
4626
+ PyErr_SetFromWindowsErr(error);
4627
+ return NULL;
4628
+ }
4629
+ */
4630
+
4631
+ struct _Py_SECURITY_ATTRIBUTE_DATA {
4632
+ SECURITY_ATTRIBUTES securityAttributes ;
4633
+ PACL acl ;
4634
+ SECURITY_DESCRIPTOR sd ;
4635
+ EXPLICIT_ACCESS_W ea [4 ];
4636
+ char sid [64 ];
4637
+ };
4638
+
4639
+ static int
4640
+ initializeDefaultSecurityAttributes (
4641
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4642
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4643
+ ) {
4644
+ assert (securityAttributes );
4645
+ assert (data );
4646
+ * securityAttributes = NULL ;
4647
+ memset (data , 0 , sizeof (* data ));
4648
+ return 0 ;
4649
+ }
4650
+
4651
+ static int
4652
+ initializeMkdir700SecurityAttributes (
4653
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4654
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4655
+ ) {
4656
+ assert (securityAttributes );
4657
+ assert (data );
4658
+ * securityAttributes = NULL ;
4659
+ memset (data , 0 , sizeof (* data ));
4660
+
4661
+ if (!InitializeSecurityDescriptor (& data -> sd , SECURITY_DESCRIPTOR_REVISION )
4662
+ || !SetSecurityDescriptorGroup (& data -> sd , NULL , TRUE)) {
4663
+ return GetLastError ();
4664
+ }
4665
+
4666
+ int use_alias = 0 ;
4667
+ DWORD cbSid = sizeof (data -> sid );
4668
+ if (!CreateWellKnownSid (WinCreatorOwnerRightsSid , NULL , (PSID )data -> sid , & cbSid )) {
4669
+ use_alias = 1 ;
4670
+ }
4671
+
4672
+ data -> securityAttributes .nLength = sizeof (SECURITY_ATTRIBUTES );
4673
+ data -> ea [0 ].grfAccessPermissions = GENERIC_ALL ;
4674
+ data -> ea [0 ].grfAccessMode = SET_ACCESS ;
4675
+ data -> ea [0 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4676
+ if (use_alias ) {
4677
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4678
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4679
+ data -> ea [0 ].Trustee .ptstrName = L"CURRENT_USER" ;
4680
+ } else {
4681
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_SID ;
4682
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP ;
4683
+ data -> ea [0 ].Trustee .ptstrName = (LPWCH )(SID * )data -> sid ;
4684
+ }
4685
+
4686
+ data -> ea [1 ].grfAccessPermissions = GENERIC_ALL ;
4687
+ data -> ea [1 ].grfAccessMode = SET_ACCESS ;
4688
+ data -> ea [1 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4689
+ data -> ea [1 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4690
+ data -> ea [1 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4691
+ data -> ea [1 ].Trustee .ptstrName = L"SYSTEM" ;
4692
+
4693
+ data -> ea [2 ].grfAccessPermissions = GENERIC_ALL ;
4694
+ data -> ea [2 ].grfAccessMode = SET_ACCESS ;
4695
+ data -> ea [2 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4696
+ data -> ea [2 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4697
+ data -> ea [2 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4698
+ data -> ea [2 ].Trustee .ptstrName = L"ADMINISTRATORS" ;
4699
+
4700
+ int r = SetEntriesInAclW (3 , data -> ea , NULL , & data -> acl );
4701
+ if (r ) {
4702
+ return r ;
4703
+ }
4704
+ if (!SetSecurityDescriptorDacl (& data -> sd , TRUE, data -> acl , FALSE)) {
4705
+ return GetLastError ();
4706
+ }
4707
+ data -> securityAttributes .lpSecurityDescriptor = & data -> sd ;
4708
+ * securityAttributes = & data -> securityAttributes ;
4709
+ return 0 ;
4710
+ }
4711
+
4712
+ static int
4713
+ clearSecurityAttributes (
4714
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4715
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4716
+ ) {
4717
+ assert (securityAttributes );
4718
+ assert (data );
4719
+ * securityAttributes = NULL ;
4720
+ if (data -> acl ) {
4721
+ if (LocalFree ((void * )data -> acl )) {
4722
+ return GetLastError ();
4723
+ }
4724
+ }
4725
+ return 0 ;
4726
+ }
4727
+
4728
+ #endif
4729
+
4585
4730
/*[clinic input]
4586
4731
os.mkdir
4587
4732
@@ -4611,6 +4756,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4611
4756
/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/
4612
4757
{
4613
4758
int result ;
4759
+ #ifdef MS_WINDOWS
4760
+ int error = 0 ;
4761
+ int pathError = 0 ;
4762
+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4763
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData ;
4764
+ #endif
4614
4765
#ifdef HAVE_MKDIRAT
4615
4766
int mkdirat_unavailable = 0 ;
4616
4767
#endif
@@ -4622,11 +4773,30 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4622
4773
4623
4774
#ifdef MS_WINDOWS
4624
4775
Py_BEGIN_ALLOW_THREADS
4625
- result = CreateDirectoryW (path -> wide , NULL );
4776
+ switch (mode ) {
4777
+ case 0x1C0 : // 0o700
4778
+ error = initializeMkdir700SecurityAttributes (& pSecAttr , & secAttrData );
4779
+ break ;
4780
+ default :
4781
+ error = initializeDefaultSecurityAttributes (& pSecAttr , & secAttrData );
4782
+ break ;
4783
+ }
4784
+ if (!error ) {
4785
+ result = CreateDirectoryW (path -> wide , pSecAttr );
4786
+ error = clearSecurityAttributes (& pSecAttr , & secAttrData );
4787
+ } else {
4788
+ // Ignore error from "clear" - we have a more interesting one already
4789
+ clearSecurityAttributes (& pSecAttr , & secAttrData );
4790
+ }
4626
4791
Py_END_ALLOW_THREADS
4627
4792
4628
- if (!result )
4793
+ if (error ) {
4794
+ PyErr_SetFromWindowsErr (error );
4795
+ return NULL ;
4796
+ }
4797
+ if (!result ) {
4629
4798
return path_error (path );
4799
+ }
4630
4800
#else
4631
4801
Py_BEGIN_ALLOW_THREADS
4632
4802
#if HAVE_MKDIRAT
0 commit comments