32
32
# include <winioctl.h>
33
33
# include <lmcons.h> // UNLEN
34
34
# include "osdefs.h" // SEP
35
+ # include <aclapi.h> // SetEntriesInAcl
36
+ # include <sddl.h> // SDDL_REVISION_1
35
37
# if defined(MS_WINDOWS_DESKTOP ) || defined(MS_WINDOWS_SYSTEM )
36
38
# define HAVE_SYMLINK
37
39
# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */
@@ -5313,6 +5315,146 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
5313
5315
return result ;
5314
5316
}
5315
5317
5318
+ #ifdef MS_WINDOWS
5319
+
5320
+ /* We centralise SECURITY_ATTRIBUTE initialization based around
5321
+ templates that will probably mostly match common POSIX mode settings.
5322
+ The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as
5323
+ a constructed SECURITY_ATTRIBUTE structure typically refers to memory
5324
+ that has to be alive while it's being used.
5325
+
5326
+ Typical use will look like:
5327
+ SECURITY_ATTRIBUTES *pSecAttr = NULL;
5328
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
5329
+ int error, error2;
5330
+
5331
+ Py_BEGIN_ALLOW_THREADS
5332
+ switch (mode) {
5333
+ case 0x1C0: // 0o700
5334
+ error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
5335
+ break;
5336
+ ...
5337
+ default:
5338
+ error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
5339
+ break;
5340
+ }
5341
+
5342
+ if (!error) {
5343
+ // do operation, passing pSecAttr
5344
+ }
5345
+
5346
+ // Unconditionally clear secAttrData.
5347
+ error2 = clearSecurityAttributes(&pSecAttr, &secAttrData);
5348
+ if (!error) {
5349
+ error = error2;
5350
+ }
5351
+ Py_END_ALLOW_THREADS
5352
+
5353
+ if (error) {
5354
+ PyErr_SetFromWindowsErr(error);
5355
+ return NULL;
5356
+ }
5357
+ */
5358
+
5359
+ struct _Py_SECURITY_ATTRIBUTE_DATA {
5360
+ SECURITY_ATTRIBUTES securityAttributes ;
5361
+ PACL acl ;
5362
+ SECURITY_DESCRIPTOR sd ;
5363
+ EXPLICIT_ACCESS_W ea [4 ];
5364
+ char sid [64 ];
5365
+ };
5366
+
5367
+ static int
5368
+ initializeDefaultSecurityAttributes (
5369
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5370
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5371
+ ) {
5372
+ assert (securityAttributes );
5373
+ assert (data );
5374
+ * securityAttributes = NULL ;
5375
+ memset (data , 0 , sizeof (* data ));
5376
+ return 0 ;
5377
+ }
5378
+
5379
+ static int
5380
+ initializeMkdir700SecurityAttributes (
5381
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5382
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5383
+ ) {
5384
+ assert (securityAttributes );
5385
+ assert (data );
5386
+ * securityAttributes = NULL ;
5387
+ memset (data , 0 , sizeof (* data ));
5388
+
5389
+ if (!InitializeSecurityDescriptor (& data -> sd , SECURITY_DESCRIPTOR_REVISION )
5390
+ || !SetSecurityDescriptorGroup (& data -> sd , NULL , TRUE)) {
5391
+ return GetLastError ();
5392
+ }
5393
+
5394
+ int use_alias = 0 ;
5395
+ DWORD cbSid = sizeof (data -> sid );
5396
+ if (!CreateWellKnownSid (WinCreatorOwnerRightsSid , NULL , (PSID )data -> sid , & cbSid )) {
5397
+ use_alias = 1 ;
5398
+ }
5399
+
5400
+ data -> securityAttributes .nLength = sizeof (SECURITY_ATTRIBUTES );
5401
+ data -> ea [0 ].grfAccessPermissions = GENERIC_ALL ;
5402
+ data -> ea [0 ].grfAccessMode = SET_ACCESS ;
5403
+ data -> ea [0 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5404
+ if (use_alias ) {
5405
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5406
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5407
+ data -> ea [0 ].Trustee .ptstrName = L"CURRENT_USER" ;
5408
+ } else {
5409
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_SID ;
5410
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP ;
5411
+ data -> ea [0 ].Trustee .ptstrName = (LPWCH )(SID * )data -> sid ;
5412
+ }
5413
+
5414
+ data -> ea [1 ].grfAccessPermissions = GENERIC_ALL ;
5415
+ data -> ea [1 ].grfAccessMode = SET_ACCESS ;
5416
+ data -> ea [1 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5417
+ data -> ea [1 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5418
+ data -> ea [1 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5419
+ data -> ea [1 ].Trustee .ptstrName = L"SYSTEM" ;
5420
+
5421
+ data -> ea [2 ].grfAccessPermissions = GENERIC_ALL ;
5422
+ data -> ea [2 ].grfAccessMode = SET_ACCESS ;
5423
+ data -> ea [2 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
5424
+ data -> ea [2 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
5425
+ data -> ea [2 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
5426
+ data -> ea [2 ].Trustee .ptstrName = L"ADMINISTRATORS" ;
5427
+
5428
+ int r = SetEntriesInAclW (3 , data -> ea , NULL , & data -> acl );
5429
+ if (r ) {
5430
+ return r ;
5431
+ }
5432
+ if (!SetSecurityDescriptorDacl (& data -> sd , TRUE, data -> acl , FALSE)) {
5433
+ return GetLastError ();
5434
+ }
5435
+ data -> securityAttributes .lpSecurityDescriptor = & data -> sd ;
5436
+ * securityAttributes = & data -> securityAttributes ;
5437
+ return 0 ;
5438
+ }
5439
+
5440
+ static int
5441
+ clearSecurityAttributes (
5442
+ PSECURITY_ATTRIBUTES * securityAttributes ,
5443
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
5444
+ ) {
5445
+ assert (securityAttributes );
5446
+ assert (data );
5447
+ * securityAttributes = NULL ;
5448
+ if (data -> acl ) {
5449
+ if (LocalFree ((void * )data -> acl )) {
5450
+ return GetLastError ();
5451
+ }
5452
+ }
5453
+ return 0 ;
5454
+ }
5455
+
5456
+ #endif
5457
+
5316
5458
/*[clinic input]
5317
5459
os.mkdir
5318
5460
@@ -5342,6 +5484,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
5342
5484
/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/
5343
5485
{
5344
5486
int result ;
5487
+ #ifdef MS_WINDOWS
5488
+ int error = 0 ;
5489
+ int pathError = 0 ;
5490
+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
5491
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData ;
5492
+ #endif
5345
5493
#ifdef HAVE_MKDIRAT
5346
5494
int mkdirat_unavailable = 0 ;
5347
5495
#endif
@@ -5353,11 +5501,30 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
5353
5501
5354
5502
#ifdef MS_WINDOWS
5355
5503
Py_BEGIN_ALLOW_THREADS
5356
- result = CreateDirectoryW (path -> wide , NULL );
5504
+ switch (mode ) {
5505
+ case 0x1C0 : // 0o700
5506
+ error = initializeMkdir700SecurityAttributes (& pSecAttr , & secAttrData );
5507
+ break ;
5508
+ default :
5509
+ error = initializeDefaultSecurityAttributes (& pSecAttr , & secAttrData );
5510
+ break ;
5511
+ }
5512
+ if (!error ) {
5513
+ result = CreateDirectoryW (path -> wide , pSecAttr );
5514
+ error = clearSecurityAttributes (& pSecAttr , & secAttrData );
5515
+ } else {
5516
+ // Ignore error from "clear" - we have a more interesting one already
5517
+ clearSecurityAttributes (& pSecAttr , & secAttrData );
5518
+ }
5357
5519
Py_END_ALLOW_THREADS
5358
5520
5359
- if (!result )
5521
+ if (error ) {
5522
+ PyErr_SetFromWindowsErr (error );
5523
+ return NULL ;
5524
+ }
5525
+ if (!result ) {
5360
5526
return path_error (path );
5527
+ }
5361
5528
#else
5362
5529
Py_BEGIN_ALLOW_THREADS
5363
5530
#if HAVE_MKDIRAT
0 commit comments