37
37
# include <winioctl.h>
38
38
# include <lmcons.h> // UNLEN
39
39
# include "osdefs.h" // SEP
40
+ # include <aclapi.h> // SetEntriesInAcl
41
+ # include <sddl.h> // SDDL_REVISION_1
40
42
# if defined(MS_WINDOWS_DESKTOP ) || defined(MS_WINDOWS_SYSTEM )
41
43
# define HAVE_SYMLINK
42
44
# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */
@@ -5539,6 +5541,133 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
5539
5541
return result ;
5540
5542
}
5541
5543
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
+ };
5591
+
5592
+ static int
5593
+ initializeDefaultSecurityAttributes (
5594
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5595
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5596
+ ) {
5597
+ assert (securityAttributes );
5598
+ assert (data );
5599
+ * securityAttributes = NULL ;
5600
+ memset (data , 0 , sizeof (* data ));
5601
+ return 0 ;
5602
+ }
5603
+
5604
+ static int
5605
+ initializeMkdir700SecurityAttributes (
5606
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5607
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5608
+ ) {
5609
+ assert (securityAttributes );
5610
+ assert (data );
5611
+ * securityAttributes = NULL ;
5612
+ memset (data , 0 , sizeof (* data ));
5613
+
5614
+ if (!InitializeSecurityDescriptor (& data -> sd , SECURITY_DESCRIPTOR_REVISION )
5615
+ || !SetSecurityDescriptorGroup (& data -> sd , NULL , TRUE)) {
5616
+ return GetLastError ();
5617
+ }
5618
+
5619
+ data -> securityAttributes .nLength = sizeof (SECURITY_ATTRIBUTES );
5620
+ data -> ea [0 ].grfAccessPermissions = GENERIC_ALL ;
5621
+ data -> ea [0 ].grfAccessMode = SET_ACCESS ;
5622
+ data -> ea [0 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5623
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5624
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5625
+ data -> ea [0 ].Trustee .ptstrName = L"CURRENT_USER" ;
5626
+
5627
+ data -> ea [1 ].grfAccessPermissions = GENERIC_ALL ;
5628
+ data -> ea [1 ].grfAccessMode = SET_ACCESS ;
5629
+ data -> ea [1 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5630
+ data -> ea [1 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5631
+ data -> ea [1 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5632
+ data -> ea [1 ].Trustee .ptstrName = L"SYSTEM" ;
5633
+
5634
+ data -> ea [2 ].grfAccessPermissions = GENERIC_ALL ;
5635
+ data -> ea [2 ].grfAccessMode = SET_ACCESS ;
5636
+ data -> ea [2 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5637
+ data -> ea [2 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5638
+ data -> ea [2 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5639
+ data -> ea [2 ].Trustee .ptstrName = L"ADMINISTRATORS" ;
5640
+
5641
+ int r = SetEntriesInAclW (3 , data -> ea , NULL , & data -> acl );
5642
+ if (r ) {
5643
+ return r ;
5644
+ }
5645
+ if (!SetSecurityDescriptorDacl (& data -> sd , TRUE, data -> acl , FALSE)) {
5646
+ return GetLastError ();
5647
+ }
5648
+ data -> securityAttributes .lpSecurityDescriptor = & data -> sd ;
5649
+ * securityAttributes = & data -> securityAttributes ;
5650
+ return 0 ;
5651
+ }
5652
+
5653
+ static int
5654
+ clearSecurityAttributes (
5655
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5656
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5657
+ ) {
5658
+ assert (securityAttributes );
5659
+ assert (data );
5660
+ * securityAttributes = NULL ;
5661
+ if (data -> acl ) {
5662
+ if (LocalFree ((void * )data -> acl )) {
5663
+ return GetLastError ();
5664
+ }
5665
+ }
5666
+ return 0 ;
5667
+ }
5668
+
5669
+ #endif
5670
+
5542
5671
/*[clinic input]
5543
5672
os.mkdir
5544
5673
@@ -5568,6 +5697,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
5568
5697
/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/
5569
5698
{
5570
5699
int result ;
5700
+ #ifdef MS_WINDOWS
5701
+ int error = 0 ;
5702
+ int pathError = 0 ;
5703
+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
5704
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData ;
5705
+ #endif
5571
5706
#ifdef HAVE_MKDIRAT
5572
5707
int mkdirat_unavailable = 0 ;
5573
5708
#endif
@@ -5579,11 +5714,30 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
5579
5714
5580
5715
#ifdef MS_WINDOWS
5581
5716
Py_BEGIN_ALLOW_THREADS
5582
- result = CreateDirectoryW (path -> wide , NULL );
5717
+ switch (mode ) {
5718
+ case 0x1C0 : // 0o700
5719
+ error = initializeMkdir700SecurityAttributes (& pSecAttr , & secAttrData );
5720
+ break ;
5721
+ default :
5722
+ error = initializeDefaultSecurityAttributes (& pSecAttr , & secAttrData );
5723
+ break ;
5724
+ }
5725
+ if (!error ) {
5726
+ result = CreateDirectoryW (path -> wide , pSecAttr );
5727
+ error = clearSecurityAttributes (& pSecAttr , & secAttrData );
5728
+ } else {
5729
+ // Ignore errors - we have a more interesting one already
5730
+ clearSecurityAttributes (& pSecAttr , & secAttrData );
5731
+ }
5583
5732
Py_END_ALLOW_THREADS
5584
5733
5585
- if (!result )
5734
+ if (error ) {
5735
+ PyErr_SetFromWindowsErr (error );
5736
+ return NULL ;
5737
+ }
5738
+ if (!result ) {
5586
5739
return path_error (path );
5740
+ }
5587
5741
#else
5588
5742
Py_BEGIN_ALLOW_THREADS
5589
5743
#if HAVE_MKDIRAT
0 commit comments