@@ -359,6 +359,171 @@ func TestBuildSecurityDescriptor(t *testing.T) {
359
359
}
360
360
}
361
361
362
+ // getEntriesFromACL returns a list of explicit access control entries associated with the given ACL.
363
+ func getEntriesFromACL (acl * windows.ACL ) (aces []* windows.ACCESS_ALLOWED_ACE , err error ) {
364
+ aces = make ([]* windows.ACCESS_ALLOWED_ACE , acl .ACECount )
365
+
366
+ for i := uint16 (0 ); i < acl .ACECount ; i ++ {
367
+ // ACECount is a word, but aceIndex is a double word.
368
+ err = windows .GetAce (acl , uint32 (i ), & aces [i ])
369
+ if err != nil {
370
+ return []* windows.ACCESS_ALLOWED_ACE {}, err
371
+ }
372
+ }
373
+
374
+ return aces , nil
375
+ }
376
+
377
+ func TestGetACEsFromACL (t * testing.T ) {
378
+ // Create a temporary file to set ACLs on and test getting the ACEs from the ACL.
379
+ f , err := os .CreateTemp ("" , "foo.lish" )
380
+ defer os .Remove (f .Name ())
381
+
382
+ f .Close ()
383
+
384
+ // Well-known SID Strings:
385
+ // https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
386
+ ownerSid , err := windows .StringToSid ("S-1-3-2" )
387
+ if err != nil {
388
+ t .Fatal (err )
389
+ }
390
+ groupSid , err := windows .StringToSid ("S-1-3-3" )
391
+ if err != nil {
392
+ t .Fatal (err )
393
+ }
394
+ worldSid , err := windows .StringToSid ("S-1-1-0" )
395
+ if err != nil {
396
+ t .Fatal (err )
397
+ }
398
+
399
+ ownerPermissions := windows .ACCESS_MASK (windows .GENERIC_ALL )
400
+ groupPermissions := windows .ACCESS_MASK (windows .GENERIC_READ | windows .GENERIC_EXECUTE )
401
+ worldPermissions := windows .ACCESS_MASK (windows .GENERIC_READ )
402
+
403
+ access := []windows.EXPLICIT_ACCESS {
404
+ {
405
+ AccessPermissions : ownerPermissions ,
406
+ AccessMode : windows .GRANT_ACCESS ,
407
+ Trustee : windows.TRUSTEE {
408
+ TrusteeForm : windows .TRUSTEE_IS_SID ,
409
+ TrusteeValue : windows .TrusteeValueFromSID (ownerSid ),
410
+ },
411
+ },
412
+ {
413
+ AccessPermissions : groupPermissions ,
414
+ AccessMode : windows .GRANT_ACCESS ,
415
+ Trustee : windows.TRUSTEE {
416
+ TrusteeForm : windows .TRUSTEE_IS_SID ,
417
+ TrusteeType : windows .TRUSTEE_IS_GROUP ,
418
+ TrusteeValue : windows .TrusteeValueFromSID (groupSid ),
419
+ },
420
+ },
421
+ {
422
+ AccessPermissions : worldPermissions ,
423
+ AccessMode : windows .GRANT_ACCESS ,
424
+ Trustee : windows.TRUSTEE {
425
+ TrusteeForm : windows .TRUSTEE_IS_SID ,
426
+ TrusteeType : windows .TRUSTEE_IS_GROUP ,
427
+ TrusteeValue : windows .TrusteeValueFromSID (worldSid ),
428
+ },
429
+ },
430
+ }
431
+
432
+ acl , err := windows .ACLFromEntries (access , nil )
433
+ if err != nil {
434
+ t .Fatal (err )
435
+ }
436
+
437
+ // Set new ACL.
438
+ err = windows .SetNamedSecurityInfo (
439
+ f .Name (),
440
+ windows .SE_FILE_OBJECT ,
441
+ windows .DACL_SECURITY_INFORMATION | windows .PROTECTED_DACL_SECURITY_INFORMATION ,
442
+ nil ,
443
+ nil ,
444
+ acl ,
445
+ nil ,
446
+ )
447
+ if err != nil {
448
+ t .Fatal (err )
449
+ }
450
+
451
+ descriptor , err := windows .GetNamedSecurityInfo (
452
+ f .Name (),
453
+ windows .SE_FILE_OBJECT ,
454
+ windows .DACL_SECURITY_INFORMATION | windows .PROTECTED_DACL_SECURITY_INFORMATION | windows .OWNER_SECURITY_INFORMATION | windows .GROUP_SECURITY_INFORMATION ,
455
+ )
456
+ if err != nil {
457
+ t .Fatal (err )
458
+ }
459
+
460
+ dacl , _ , err := descriptor .DACL ()
461
+ if err != nil {
462
+ t .Fatal (err )
463
+ }
464
+
465
+ owner , _ , err := descriptor .Owner ()
466
+ if err != nil {
467
+ t .Fatal (err )
468
+ }
469
+
470
+ group , _ , err := descriptor .Group ()
471
+ if err != nil {
472
+ t .Fatal (err )
473
+ }
474
+
475
+ entries , err := getEntriesFromACL (dacl )
476
+ if err != nil {
477
+ t .Fatal (err )
478
+ }
479
+
480
+ if len (entries ) != 3 {
481
+ t .Fatalf ("Expected newly set ACL to only have 3 entries." )
482
+ }
483
+
484
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
485
+ // read = read data | read attributes
486
+ read := 0x0001 | 0x0080
487
+
488
+ // write = write data | append data | write attributes | write EA
489
+ write := 0x0002 | 0x0004 | 0x0100 | 0x0010
490
+
491
+ // execute = read data | file execute
492
+ execute := 0x0001 | 0x0020
493
+
494
+ // Check the set ACEs. We should have the equivalent of 754.
495
+ for _ , entry := range entries {
496
+ mask := int (entry .Mask )
497
+ actual := 0
498
+
499
+ if mask & read == read {
500
+ actual |= 4
501
+ }
502
+ if mask & write == write {
503
+ actual |= 2
504
+ }
505
+ if mask & execute == execute {
506
+ actual |= 1
507
+ }
508
+
509
+ if owner .Equals (& entry .Sid ) {
510
+ if actual != 7 {
511
+ t .Fatalf ("Expected owner to have FullAccess permissions." )
512
+ }
513
+ } else if group .Equals (& entry .Sid ) {
514
+ if actual != 5 {
515
+ t .Fatalf ("Expected group to have only Read and Execute permissions." )
516
+ }
517
+ } else if worldSid .Equals (& entry .Sid ) {
518
+ if actual != 4 {
519
+ t .Fatalf ("Expected the World to have only Read permissions." )
520
+ }
521
+ } else {
522
+ t .Fatalf ("Unexpected SID in ACEs: %s" , (& entry .Sid ).String ())
523
+ }
524
+ }
525
+ }
526
+
362
527
func TestGetDiskFreeSpaceEx (t * testing.T ) {
363
528
cwd , err := windows .UTF16PtrFromString ("." )
364
529
if err != nil {
0 commit comments