40
40
#include "pycore_pystate.h" /* _PyRuntime */
41
41
#include "pythread.h"
42
42
#include "structmember.h"
43
+
44
+ #ifdef MS_WINDOWS
45
+ # include <aclapi.h> // SetEntriesInAcl
46
+ # include <sddl.h> // SDDL_REVISION_1
47
+ #endif
48
+
43
49
#ifndef MS_WINDOWS
44
50
# include "posixmodule.h"
45
51
#else
@@ -4123,6 +4129,146 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
4123
4129
#endif /* MS_WINDOWS */
4124
4130
4125
4131
4132
+ #ifdef MS_WINDOWS
4133
+
4134
+ /* We centralise SECURITY_ATTRIBUTE initialization based around
4135
+ templates that will probably mostly match common POSIX mode settings.
4136
+ The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as
4137
+ a constructed SECURITY_ATTRIBUTE structure typically refers to memory
4138
+ that has to be alive while it's being used.
4139
+
4140
+ Typical use will look like:
4141
+ SECURITY_ATTRIBUTES *pSecAttr = NULL;
4142
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData;
4143
+ int error, error2;
4144
+
4145
+ Py_BEGIN_ALLOW_THREADS
4146
+ switch (mode) {
4147
+ case 0x1C0: // 0o700
4148
+ error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData);
4149
+ break;
4150
+ ...
4151
+ default:
4152
+ error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData);
4153
+ break;
4154
+ }
4155
+
4156
+ if (!error) {
4157
+ // do operation, passing pSecAttr
4158
+ }
4159
+
4160
+ // Unconditionally clear secAttrData.
4161
+ error2 = clearSecurityAttributes(&pSecAttr, &secAttrData);
4162
+ if (!error) {
4163
+ error = error2;
4164
+ }
4165
+ Py_END_ALLOW_THREADS
4166
+
4167
+ if (error) {
4168
+ PyErr_SetFromWindowsErr(error);
4169
+ return NULL;
4170
+ }
4171
+ */
4172
+
4173
+ struct _Py_SECURITY_ATTRIBUTE_DATA {
4174
+ SECURITY_ATTRIBUTES securityAttributes ;
4175
+ PACL acl ;
4176
+ SECURITY_DESCRIPTOR sd ;
4177
+ EXPLICIT_ACCESS_W ea [4 ];
4178
+ char sid [64 ];
4179
+ };
4180
+
4181
+ static int
4182
+ initializeDefaultSecurityAttributes (
4183
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4184
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4185
+ ) {
4186
+ assert (securityAttributes );
4187
+ assert (data );
4188
+ * securityAttributes = NULL ;
4189
+ memset (data , 0 , sizeof (* data ));
4190
+ return 0 ;
4191
+ }
4192
+
4193
+ static int
4194
+ initializeMkdir700SecurityAttributes (
4195
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4196
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4197
+ ) {
4198
+ assert (securityAttributes );
4199
+ assert (data );
4200
+ * securityAttributes = NULL ;
4201
+ memset (data , 0 , sizeof (* data ));
4202
+
4203
+ if (!InitializeSecurityDescriptor (& data -> sd , SECURITY_DESCRIPTOR_REVISION )
4204
+ || !SetSecurityDescriptorGroup (& data -> sd , NULL , TRUE)) {
4205
+ return GetLastError ();
4206
+ }
4207
+
4208
+ int use_alias = 0 ;
4209
+ DWORD cbSid = sizeof (data -> sid );
4210
+ if (!CreateWellKnownSid (WinCreatorOwnerRightsSid , NULL , (PSID )data -> sid , & cbSid )) {
4211
+ use_alias = 1 ;
4212
+ }
4213
+
4214
+ data -> securityAttributes .nLength = sizeof (SECURITY_ATTRIBUTES );
4215
+ data -> ea [0 ].grfAccessPermissions = GENERIC_ALL ;
4216
+ data -> ea [0 ].grfAccessMode = SET_ACCESS ;
4217
+ data -> ea [0 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4218
+ if (use_alias ) {
4219
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4220
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4221
+ data -> ea [0 ].Trustee .ptstrName = L"CURRENT_USER" ;
4222
+ } else {
4223
+ data -> ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_SID ;
4224
+ data -> ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP ;
4225
+ data -> ea [0 ].Trustee .ptstrName = (LPWCH )(SID * )data -> sid ;
4226
+ }
4227
+
4228
+ data -> ea [1 ].grfAccessPermissions = GENERIC_ALL ;
4229
+ data -> ea [1 ].grfAccessMode = SET_ACCESS ;
4230
+ data -> ea [1 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4231
+ data -> ea [1 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4232
+ data -> ea [1 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4233
+ data -> ea [1 ].Trustee .ptstrName = L"SYSTEM" ;
4234
+
4235
+ data -> ea [2 ].grfAccessPermissions = GENERIC_ALL ;
4236
+ data -> ea [2 ].grfAccessMode = SET_ACCESS ;
4237
+ data -> ea [2 ].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT ;
4238
+ data -> ea [2 ].Trustee .TrusteeForm = TRUSTEE_IS_NAME ;
4239
+ data -> ea [2 ].Trustee .TrusteeType = TRUSTEE_IS_ALIAS ;
4240
+ data -> ea [2 ].Trustee .ptstrName = L"ADMINISTRATORS" ;
4241
+
4242
+ int r = SetEntriesInAclW (3 , data -> ea , NULL , & data -> acl );
4243
+ if (r ) {
4244
+ return r ;
4245
+ }
4246
+ if (!SetSecurityDescriptorDacl (& data -> sd , TRUE, data -> acl , FALSE)) {
4247
+ return GetLastError ();
4248
+ }
4249
+ data -> securityAttributes .lpSecurityDescriptor = & data -> sd ;
4250
+ * securityAttributes = & data -> securityAttributes ;
4251
+ return 0 ;
4252
+ }
4253
+
4254
+ static int
4255
+ clearSecurityAttributes (
4256
+ PSECURITY_ATTRIBUTES * securityAttributes ,
4257
+ struct _Py_SECURITY_ATTRIBUTE_DATA * data
4258
+ ) {
4259
+ assert (securityAttributes );
4260
+ assert (data );
4261
+ * securityAttributes = NULL ;
4262
+ if (data -> acl ) {
4263
+ if (LocalFree ((void * )data -> acl )) {
4264
+ return GetLastError ();
4265
+ }
4266
+ }
4267
+ return 0 ;
4268
+ }
4269
+
4270
+ #endif
4271
+
4126
4272
/*[clinic input]
4127
4273
os.mkdir
4128
4274
@@ -4151,6 +4297,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4151
4297
/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
4152
4298
{
4153
4299
int result ;
4300
+ #ifdef MS_WINDOWS
4301
+ int error = 0 ;
4302
+ int pathError = 0 ;
4303
+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4304
+ struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData ;
4305
+ #endif
4154
4306
4155
4307
if (PySys_Audit ("os.mkdir" , "Oii" , path -> object , mode ,
4156
4308
dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd ) < 0 ) {
@@ -4159,11 +4311,30 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4159
4311
4160
4312
#ifdef MS_WINDOWS
4161
4313
Py_BEGIN_ALLOW_THREADS
4162
- result = CreateDirectoryW (path -> wide , NULL );
4314
+ switch (mode ) {
4315
+ case 0x1C0 : // 0o700
4316
+ error = initializeMkdir700SecurityAttributes (& pSecAttr , & secAttrData );
4317
+ break ;
4318
+ default :
4319
+ error = initializeDefaultSecurityAttributes (& pSecAttr , & secAttrData );
4320
+ break ;
4321
+ }
4322
+ if (!error ) {
4323
+ result = CreateDirectoryW (path -> wide , pSecAttr );
4324
+ error = clearSecurityAttributes (& pSecAttr , & secAttrData );
4325
+ } else {
4326
+ // Ignore error from "clear" - we have a more interesting one already
4327
+ clearSecurityAttributes (& pSecAttr , & secAttrData );
4328
+ }
4163
4329
Py_END_ALLOW_THREADS
4164
4330
4165
- if (!result )
4331
+ if (error ) {
4332
+ PyErr_SetFromWindowsErr (error );
4333
+ return NULL ;
4334
+ }
4335
+ if (!result ) {
4166
4336
return path_error (path );
4337
+ }
4167
4338
#else
4168
4339
Py_BEGIN_ALLOW_THREADS
4169
4340
#if HAVE_MKDIRAT
0 commit comments