-
Notifications
You must be signed in to change notification settings - Fork 231
/
Copy pathsddlHelper_linux.go
1719 lines (1488 loc) · 61.1 KB
/
sddlHelper_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//go:build linux
// +build linux
// Copyright Microsoft <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package sddl
import (
"encoding/binary"
"fmt"
"strconv"
"unsafe"
"github.com/Azure/azure-storage-azcopy/v10/common"
"github.com/pkg/xattr"
)
/*
* Following constants are used by various Windows functions that deal with SECURITY_DESCRIPTORs and SIDs.
* Most of these constants are originally defined in winnt.h
*/
/*
* Valid/supported revision numbers for various object types.
*
* TODO: Do we need to support ACL_REVISION_DS (4) with support for Object ACEs?
* Are they used for filesystem objects?
*/
const (
SDDL_REVISION = 1 // SDDL Revision MUST always be 1.
SID_REVISION = 1 // SID Revision MUST always be 1.
ACL_REVISION = 2 // ACL revision for support basic ACE type used for filesystem ACLs.
ACL_REVISION_DS = 4 // ACL revision for supporting stuff like Object ACE. This should ideally not be used with the ACE
// types we support, but I've seen some objects like that.
)
type SECURITY_INFORMATION uint32
// Valid bitmasks contained in type SECURITY_INFORMATION.
const (
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
SCOPE_SECURITY_INFORMATION = 0x00000040
BACKUP_SECURITY_INFORMATION = 0x00010000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)
// Valid bitmasks contained in type SECURITY_DESCRIPTOR_CONTROL.
const (
SE_OWNER_DEFAULTED = 0x0001
SE_GROUP_DEFAULTED = 0x0002
SE_DACL_PRESENT = 0x0004
SE_DACL_DEFAULTED = 0x0008
SE_SACL_PRESENT = 0x0010
SE_SACL_DEFAULTED = 0x0020
SE_DACL_AUTO_INHERIT_REQ = 0x0100
SE_SACL_AUTO_INHERIT_REQ = 0x0200
SE_DACL_AUTO_INHERITED = 0x0400
SE_SACL_AUTO_INHERITED = 0x0800
SE_DACL_PROTECTED = 0x1000
SE_SACL_PROTECTED = 0x2000
SE_RM_CONTROL_VALID = 0x4000
SE_SELF_RELATIVE = 0x8000
)
// Valid AceType values present in ACE_HEADER.
const (
ACCESS_MIN_MS_ACE_TYPE = 0x0
ACCESS_ALLOWED_ACE_TYPE = 0x0
ACCESS_DENIED_ACE_TYPE = 0x1
SYSTEM_AUDIT_ACE_TYPE = 0x2
SYSTEM_ALARM_ACE_TYPE = 0x3
ACCESS_MAX_MS_V2_ACE_TYPE = 0x3
ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 0x4
ACCESS_MAX_MS_V3_ACE_TYPE = 0x4
ACCESS_MIN_MS_OBJECT_ACE_TYPE = 0x5
ACCESS_ALLOWED_OBJECT_ACE_TYPE = 0x5
ACCESS_DENIED_OBJECT_ACE_TYPE = 0x6
SYSTEM_AUDIT_OBJECT_ACE_TYPE = 0x7
SYSTEM_ALARM_OBJECT_ACE_TYPE = 0x8
ACCESS_MAX_MS_OBJECT_ACE_TYPE = 0x8
ACCESS_MAX_MS_V4_ACE_TYPE = 0x8
ACCESS_MAX_MS_ACE_TYPE = 0x8
ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 0x9
ACCESS_DENIED_CALLBACK_ACE_TYPE = 0xA
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 0xB
ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 0xC
SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 0xD
SYSTEM_ALARM_CALLBACK_ACE_TYPE = 0xE
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 0xF
SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 0x10
SYSTEM_MANDATORY_LABEL_ACE_TYPE = 0x11
SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE = 0x12
SYSTEM_SCOPED_POLICY_ID_ACE_TYPE = 0x13
SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE = 0x14
SYSTEM_ACCESS_FILTER_ACE_TYPE = 0x15
ACCESS_MAX_MS_V5_ACE_TYPE = 0x15
)
var aceTypeStringMap = map[string]BYTE{
"A": ACCESS_ALLOWED_ACE_TYPE,
"D": ACCESS_DENIED_ACE_TYPE,
"OA": ACCESS_ALLOWED_OBJECT_ACE_TYPE,
"OD": ACCESS_DENIED_OBJECT_ACE_TYPE,
"AU": SYSTEM_AUDIT_ACE_TYPE,
"AL": SYSTEM_ALARM_ACE_TYPE,
"OU": SYSTEM_AUDIT_OBJECT_ACE_TYPE,
"OL": SYSTEM_ALARM_OBJECT_ACE_TYPE,
"ML": SYSTEM_MANDATORY_LABEL_ACE_TYPE,
"XA": ACCESS_ALLOWED_CALLBACK_ACE_TYPE,
"XD": ACCESS_DENIED_CALLBACK_ACE_TYPE,
"RA": SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE,
"SP": SYSTEM_SCOPED_POLICY_ID_ACE_TYPE,
"XU": SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE,
"ZA": ACCESS_ALLOWED_CALLBACK_ACE_TYPE,
"TL": SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE,
"FL": SYSTEM_ACCESS_FILTER_ACE_TYPE,
}
// Valid bitmasks contained in AceFlags present in ACE_HEADER.
const (
OBJECT_INHERIT_ACE = 0x01
CONTAINER_INHERIT_ACE = 0x02
NO_PROPAGATE_INHERIT_ACE = 0x04
INHERIT_ONLY_ACE = 0x08
INHERITED_ACE = 0x10
VALID_INHERIT_FLAGS = 0x1F
CRITICAL_ACE_FLAG = 0x20
// AceFlags mask for what events we (should) audit. Used by SACL.
SUCCESSFUL_ACCESS_ACE_FLAG = 0x40
FAILED_ACCESS_ACE_FLAG = 0x80
TRUST_PROTECTED_FILTER_ACE_FLAG = 0x40
)
// Valid bitmasks contained in AccessMask present in type ACCESS_ALLOWED_ACE.
const (
// Generic access rights.
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
DELETE = 0x00010000
READ_CONTROL = 0x00020000
WRITE_DAC = 0x00040000
WRITE_OWNER = 0x00080000
SYNCHRONIZE = 0x00100000
STANDARD_RIGHTS_REQUIRED = 0x000F0000
STANDARD_RIGHTS_READ = READ_CONTROL
STANDARD_RIGHTS_WRITE = READ_CONTROL
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
STANDARD_RIGHTS_ALL = 0x001F0000
SPECIFIC_RIGHTS_ALL = 0x0000FFFF
// Access rights for files and directories.
FILE_READ_DATA = 0x0001 /* file & pipe */
FILE_READ_ATTRIBUTES = 0x0080 /* all */
FILE_READ_EA = 0x0008 /* file & directory */
FILE_WRITE_DATA = 0x0002 /* file & pipe */
FILE_WRITE_ATTRIBUTES = 0x0100 /* all */
FILE_WRITE_EA = 0x0010 /* file & directory */
FILE_APPEND_DATA = 0x0004 /* file */
FILE_EXECUTE = 0x0020 /* file */
FILE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
FILE_GENERIC_READ = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
FILE_GENERIC_EXECUTE = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
// Access rights for DS objects.
ADS_RIGHT_DS_CREATE_CHILD = 0x0001
ADS_RIGHT_DS_DELETE_CHILD = 0x0002
ADS_RIGHT_ACTRL_DS_LIST = 0x0004
ADS_RIGHT_DS_SELF = 0x0008
ADS_RIGHT_DS_READ_PROP = 0x0010
ADS_RIGHT_DS_WRITE_PROP = 0x0020
ADS_RIGHT_DS_DELETE_TREE = 0x0040
ADS_RIGHT_DS_LIST_OBJECT = 0x0080
ADS_RIGHT_DS_CONTROL_ACCESS = 0x0100
// Registry Specific Access Rights.
KEY_QUERY_VALUE = 0x0001
KEY_SET_VALUE = 0x0002
KEY_CREATE_SUB_KEY = 0x0004
KEY_ENUMERATE_SUB_KEYS = 0x0008
KEY_NOTIFY = 0x0010
KEY_CREATE_LINK = 0x0020
KEY_WOW64_32KEY = 0x0200
KEY_WOW64_64KEY = 0x0100
KEY_WOW64_RES = 0x0300
KEY_READ = ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (^SYNCHRONIZE))
KEY_WRITE = ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (^SYNCHRONIZE))
KEY_EXECUTE = ((KEY_READ) & (^SYNCHRONIZE))
KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (^SYNCHRONIZE))
// SYSTEM_ACCESS_FILTER_ACE Access rights.
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP = 0x1
SYSTEM_MANDATORY_LABEL_NO_READ_UP = 0x2
SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP = 0x4
)
// Access mask exactly matching the value here will be mapped to the key.
var aceStringToRightsMap = map[string]uint32{
"GA": GENERIC_ALL,
"GR": GENERIC_READ,
"GW": GENERIC_WRITE,
"GX": GENERIC_EXECUTE,
"RC": READ_CONTROL,
"SD": DELETE,
"WD": WRITE_DAC,
"WO": WRITE_OWNER,
"RP": ADS_RIGHT_DS_READ_PROP,
"WP": ADS_RIGHT_DS_WRITE_PROP,
"CC": ADS_RIGHT_DS_CREATE_CHILD,
"DC": ADS_RIGHT_DS_DELETE_CHILD,
"LC": ADS_RIGHT_ACTRL_DS_LIST,
"SW": ADS_RIGHT_DS_SELF,
"LO": ADS_RIGHT_DS_LIST_OBJECT,
"DT": ADS_RIGHT_DS_DELETE_TREE,
"CR": ADS_RIGHT_DS_CONTROL_ACCESS,
"FA": FILE_ALL_ACCESS,
"FR": FILE_GENERIC_READ,
"FW": FILE_GENERIC_WRITE,
"FX": FILE_GENERIC_EXECUTE,
"KA": KEY_ALL_ACCESS,
"KR": KEY_READ,
"KW": KEY_WRITE,
"KX": KEY_EXECUTE,
"NR": SYSTEM_MANDATORY_LABEL_NO_READ_UP,
"NW": SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
"NX": SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
}
// Access rights to their corresponding friendly names.
// Note that this intentionally has some of the fields left out from aceStringToRightsMap.
var aceRightsToStringMap = map[uint32]string{
GENERIC_ALL: "GA",
GENERIC_READ: "GR",
GENERIC_WRITE: "GW",
GENERIC_EXECUTE: "GX",
READ_CONTROL: "RC",
DELETE: "SD",
WRITE_DAC: "WD",
WRITE_OWNER: "WO",
ADS_RIGHT_DS_READ_PROP: "RP",
ADS_RIGHT_DS_WRITE_PROP: "WP",
ADS_RIGHT_DS_CREATE_CHILD: "CC",
ADS_RIGHT_DS_DELETE_CHILD: "DC",
ADS_RIGHT_ACTRL_DS_LIST: "LC",
ADS_RIGHT_DS_SELF: "SW",
ADS_RIGHT_DS_LIST_OBJECT: "LO",
ADS_RIGHT_DS_DELETE_TREE: "DT",
ADS_RIGHT_DS_CONTROL_ACCESS: "CR",
}
var (
SECURITY_NULL_SID_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 0}
SECURITY_WORLD_SID_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 1}
SECURITY_LOCAL_SID_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 2}
SECURITY_CREATOR_SID_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 3}
SECURITY_NON_UNIQUE_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 4}
SECURITY_NT_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 5}
SECURITY_APP_PACKAGE_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 15}
SECURITY_MANDATORY_LABEL_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 16}
SECURITY_SCOPED_POLICY_ID_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 17}
SECURITY_AUTHENTICATION_AUTHORITY = [6]byte{0, 0, 0, 0, 0, 18}
)
const (
SECURITY_NULL_RID = 0
SECURITY_WORLD_RID = 0
SECURITY_LOCAL_RID = 0
SECURITY_CREATOR_OWNER_RID = 0
SECURITY_CREATOR_GROUP_RID = 1
SECURITY_DIALUP_RID = 1
SECURITY_NETWORK_RID = 2
SECURITY_BATCH_RID = 3
SECURITY_INTERACTIVE_RID = 4
SECURITY_LOGON_IDS_RID = 5
SECURITY_SERVICE_RID = 6
SECURITY_LOCAL_SYSTEM_RID = 18
SECURITY_BUILTIN_DOMAIN_RID = 32
SECURITY_PRINCIPAL_SELF_RID = 10
SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
SECURITY_LOGON_IDS_RID_COUNT = 0x3
SECURITY_ANONYMOUS_LOGON_RID = 0x7
SECURITY_PROXY_RID = 0x8
SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
SECURITY_AUTHENTICATED_USER_RID = 0xb
SECURITY_RESTRICTED_CODE_RID = 0xc
SECURITY_NT_NON_UNIQUE_RID = 0x15
SECURITY_CREATOR_OWNER_RIGHTS_RID = 0x00000004
SECURITY_LOCAL_SERVICE_RID = 0x00000013
SECURITY_NETWORK_SERVICE_RID = 0x00000014
SECURITY_WRITE_RESTRICTED_CODE_RID = 0x00000021
SECURITY_MANDATORY_LOW_RID = 0x00001000
SECURITY_MANDATORY_MEDIUM_RID = 0x00002000
SECURITY_MANDATORY_MEDIUM_PLUS_RID = (SECURITY_MANDATORY_MEDIUM_RID + 0x100)
SECURITY_MANDATORY_HIGH_RID = 0x00003000
SECURITY_MANDATORY_SYSTEM_RID = 0x00004000
SECURITY_APP_PACKAGE_BASE_RID = 0x00000002
SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE = 0x00000001
)
// Predefined domain-relative RIDs for local groups.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379649(v=vs.85).aspx
const (
DOMAIN_ALIAS_RID_ADMINS = 0x220
DOMAIN_ALIAS_RID_USERS = 0x221
DOMAIN_ALIAS_RID_GUESTS = 0x222
DOMAIN_ALIAS_RID_POWER_USERS = 0x223
DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224
DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225
DOMAIN_ALIAS_RID_PRINT_OPS = 0x226
DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227
DOMAIN_ALIAS_RID_REPLICATOR = 0x228
DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229
DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22A
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS = 0x22B
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS = 0x22C
DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 0x22D
DOMAIN_ALIAS_RID_MONITORING_USERS = 0x22E
DOMAIN_ALIAS_RID_LOGGING_USERS = 0x22F
DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS = 0x230
DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS = 0x231
DOMAIN_ALIAS_RID_DCOM_USERS = 0x232
DOMAIN_ALIAS_RID_IUSERS = 0x238
DOMAIN_ALIAS_RID_CRYPTO_OPERATORS = 0x239
DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP = 0x23B
DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 0x23C
DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP = 0x23D
DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP = 0x23E
DOMAIN_ALIAS_RID_RDS_REMOTE_ACCESS_SERVERS = 0x23F
DOMAIN_ALIAS_RID_RDS_ENDPOINT_SERVERS = 0x240
DOMAIN_ALIAS_RID_RDS_MANAGEMENT_SERVERS = 0x241
DOMAIN_ALIAS_RID_HYPER_V_ADMINS = 0x242
DOMAIN_ALIAS_RID_ACCESS_CONTROL_ASSISTANCE_OPS = 0x243
DOMAIN_ALIAS_RID_REMOTE_MANAGEMENT_USERS = 0x244
DOMAIN_ALIAS_RID_DEFAULT_ACCOUNT = 0x245
DOMAIN_ALIAS_RID_STORAGE_REPLICA_ADMINS = 0x246
DOMAIN_ALIAS_RID_DEVICE_OWNERS = 0x247
)
const (
DOMAIN_GROUP_RID_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS = 0x1F2 // 498
DOMAIN_USER_RID_ADMIN = 0x1F4 // 500
DOMAIN_USER_RID_GUEST = 0x1F5
DOMAIN_GROUP_RID_ADMINS = 0x200 // 512
DOMAIN_GROUP_RID_USERS = 0x201
DOMAIN_GROUP_RID_GUESTS = 0x202
DOMAIN_GROUP_RID_COMPUTERS = 0x203
DOMAIN_GROUP_RID_CONTROLLERS = 0x204
DOMAIN_GROUP_RID_CERT_ADMINS = 0x205
DOMAIN_GROUP_RID_SCHEMA_ADMINS = 0x206
DOMAIN_GROUP_RID_ENTERPRISE_ADMINS = 0x207
DOMAIN_GROUP_RID_POLICY_ADMINS = 0x208
DOMAIN_GROUP_RID_READONLY_CONTROLLERS = 0x209
DOMAIN_GROUP_RID_CLONEABLE_CONTROLLERS = 0x20A
DOMAIN_GROUP_RID_CDC_RESERVED = 0x20C
DOMAIN_GROUP_RID_PROTECTED_USERS = 0x20D
DOMAIN_GROUP_RID_KEY_ADMINS = 0x20E
DOMAIN_GROUP_RID_ENTERPRISE_KEY_ADMINS = 0x20F
)
const (
SECURITY_AUTHENTICATION_AUTHORITY_ASSERTED_RID = 0x1
SECURITY_AUTHENTICATION_SERVICE_ASSERTED_RID = 0x2
SECURITY_AUTHENTICATION_FRESH_KEY_AUTH_RID = 0x3
SECURITY_AUTHENTICATION_KEY_TRUST_RID = 0x4
SECURITY_AUTHENTICATION_KEY_PROPERTY_MFA_RID = 0x5
SECURITY_AUTHENTICATION_KEY_PROPERTY_ATTESTATION_RID = 0x6
)
/*
* Define some Windows type names for increased readability of various Windows structs we use here.
*/
type BYTE byte
type WORD uint16
type DWORD uint32
/****************************************************************************
* Various binary structures used for conveying SMB objects.
*
* ALL MULTI-BYTE VALUES ARE IN LITTLE ENDIAN FORMAT.
*
* We don't use these structures in the code but they are there to help reader
* understand the code.
****************************************************************************/
/*
* This is NT Security Descriptor in "Self Relative" format.
* This is returned when common.CIFS_XATTR_CIFS_NTSD xattr is queried for a file.
* The Linux equivalent struct is "struct cifs_ntsd".
*/
type SECURITY_DESCRIPTOR_CONTROL WORD
type SECURITY_DESCRIPTOR_RELATIVE struct {
// Revision number of this SECURITY_DESCRIPTOR. Must be 1.
Revision BYTE
// Zero byte.
Sbz1 BYTE
// Flag bits describing this SECURITY_DESCRIPTOR.
Control SECURITY_DESCRIPTOR_CONTROL
// Offset of owner sid. There's a SID structure at this offset.
OffsetOwner DWORD
// Offset of primary group sid. There's a SID structure at this offset.
OffsetGroup DWORD
// Offset of SACL. There's an ACL structure at this offset.
OffsetSacl DWORD
// Offset of DACL. There's an ACL structure at this offset.
OffsetDacl DWORD
// 0 or more bytes (depending on the various offsets above) follow this structure.
Data [0]BYTE
}
// Maximum sub authority values present in a SID.
const SID_MAX_SUB_AUTHORITIES = 15
/*
* SID structure.
* The Linux equivalent struct is "struct cifs_sid".
*/
type SID struct {
Revision BYTE
// How many DWORD SubAuthority values? Cannot be 0, max possible value is SID_MAX_SUB_AUTHORITIES.
SubAuthorityCount BYTE
// IdentifierAuthority is in big endian format.
IdentifierAuthority [6]BYTE
// SubAuthorityCount SubAuthority DWORDs.
SubAuthority [1]DWORD
}
/*
* Header at the beginning of every ACE.
*/
type ACE_HEADER struct {
AceType BYTE
AceFlags BYTE
AceSize WORD
}
/*
* Single ACE (Access Check Entry).
* One or more of these are contained in ACL.
* The Linux equivalent struct is "struct cifs_ace".
*/
type ACCESS_ALLOWED_ACE struct {
Header ACE_HEADER
// What permissions is this ACE controlling?
AccessMask DWORD
// SID to which these permissions apply.
Sid SID
}
/*
* Binary ACL format. Used for both DACL and SACL.
* The Linux equivalent struct is "struct cifs_acl".
*/
type ACL struct {
AclRevision BYTE
Sbz1 BYTE
AclSize WORD
AceCount WORD
Sbz2 WORD
}
type AnySID struct {
Revision byte
SubAuthorityCount byte
IdentifierAuthority [6]byte
SubAuthority []uint32
}
// TODO: Validate completeness/correctness.
var wellKnownSidShortcuts = map[string]AnySID{
"WD": {SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, []uint32{SECURITY_NULL_RID}},
"CO": {SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, []uint32{SECURITY_CREATOR_OWNER_RID}},
"CG": {SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, []uint32{SECURITY_CREATOR_GROUP_RID}},
"OW": {SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, []uint32{SECURITY_CREATOR_OWNER_RIGHTS_RID}},
"NU": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_NETWORK_RID}},
"IU": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_INTERACTIVE_RID}},
"SU": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_SERVICE_RID}},
"AN": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_ANONYMOUS_LOGON_RID}},
"ED": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_ENTERPRISE_CONTROLLERS_RID}},
"PS": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_PRINCIPAL_SELF_RID}},
"AU": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_AUTHENTICATED_USER_RID}},
"RC": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_RESTRICTED_CODE_RID}},
"SY": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_LOCAL_SYSTEM_RID}},
"LS": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_LOCAL_SERVICE_RID}},
"NS": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_NETWORK_SERVICE_RID}},
"WR": {SID_REVISION, 1, SECURITY_NT_AUTHORITY, []uint32{SECURITY_WRITE_RESTRICTED_CODE_RID}},
"BA": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS}},
"BU": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS}},
"BG": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS}},
"PU": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS}},
"AO": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS}},
"SO": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS}},
"PO": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS}},
"BO": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS}},
"RE": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR}},
"RU": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS}},
"RD": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS}},
"NO": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS}},
"MU": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_MONITORING_USERS}},
"LU": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_LOGGING_USERS}},
"IS": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_IUSERS}},
"CY": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_CRYPTO_OPERATORS}},
"ER": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP}},
"CD": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP}},
"RA": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_RDS_REMOTE_ACCESS_SERVERS}},
"ES": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_RDS_ENDPOINT_SERVERS}},
"MS": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_RDS_MANAGEMENT_SERVERS}},
"HA": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_HYPER_V_ADMINS}},
"AA": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCESS_CONTROL_ASSISTANCE_OPS}},
"RM": {SID_REVISION, 2, SECURITY_NT_AUTHORITY, []uint32{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REMOTE_MANAGEMENT_USERS}},
"LW": {SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, []uint32{SECURITY_MANDATORY_LOW_RID}},
"ME": {SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, []uint32{SECURITY_MANDATORY_MEDIUM_RID}},
"MP": {SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, []uint32{SECURITY_MANDATORY_MEDIUM_PLUS_RID}},
"HI": {SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, []uint32{SECURITY_MANDATORY_HIGH_RID}},
"SI": {SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, []uint32{SECURITY_MANDATORY_SYSTEM_RID}},
"AC": {SID_REVISION, 2, SECURITY_APP_PACKAGE_AUTHORITY, []uint32{SECURITY_APP_PACKAGE_BASE_RID, SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE}},
"AS": {SID_REVISION, 1, SECURITY_AUTHENTICATION_AUTHORITY, []uint32{SECURITY_AUTHENTICATION_AUTHORITY_ASSERTED_RID}},
"SS": {SID_REVISION, 1, SECURITY_AUTHENTICATION_AUTHORITY, []uint32{SECURITY_AUTHENTICATION_SERVICE_ASSERTED_RID}},
}
// TODO: Validate completeness/correctness.
var domainRidShortcuts = map[string]uint32{
"RO": DOMAIN_GROUP_RID_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS,
"LA": DOMAIN_USER_RID_ADMIN,
"LG": DOMAIN_USER_RID_GUEST,
"DA": DOMAIN_GROUP_RID_ADMINS,
"DU": DOMAIN_GROUP_RID_USERS,
"DG": DOMAIN_GROUP_RID_GUESTS,
"DC": DOMAIN_GROUP_RID_COMPUTERS,
"DD": DOMAIN_GROUP_RID_CONTROLLERS,
"CA": DOMAIN_GROUP_RID_CERT_ADMINS,
"SA": DOMAIN_GROUP_RID_SCHEMA_ADMINS,
"EA": DOMAIN_GROUP_RID_ENTERPRISE_ADMINS,
"PA": DOMAIN_GROUP_RID_POLICY_ADMINS,
"CN": DOMAIN_GROUP_RID_CLONEABLE_CONTROLLERS,
"AP": DOMAIN_GROUP_RID_PROTECTED_USERS,
"KA": DOMAIN_GROUP_RID_KEY_ADMINS,
"EK": DOMAIN_GROUP_RID_ENTERPRISE_KEY_ADMINS,
"RS": DOMAIN_ALIAS_RID_RAS_SERVERS,
}
/****************************************************************************/
// Test whether sd refers to a valid Security Descriptor.
// We do some basic validations of the SECURITY_DESCRIPTOR_RELATIVE header.
// 'flags' is used to convey what all information does the caller want us to verify in the binary SD.
func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error {
if len(sd) < int(unsafe.Sizeof(SECURITY_DESCRIPTOR_RELATIVE{})) {
return fmt.Errorf("sd too small (%d bytes)", len(sd))
}
// Fetch various fields of the Security Descriptor.
revision := sd[0]
sbz1 := sd[1]
control := binary.LittleEndian.Uint16(sd[2:4])
offsetOwner := binary.LittleEndian.Uint32(sd[4:8])
offsetGroup := binary.LittleEndian.Uint32(sd[8:12])
offsetSacl := binary.LittleEndian.Uint32(sd[12:16])
offsetDacl := binary.LittleEndian.Uint32(sd[16:20])
// Now validate sanity of these fields.
if revision != SDDL_REVISION {
return fmt.Errorf("Invalid SD revision (%d), expected %d", revision, SDDL_REVISION)
}
if sbz1 != 0 {
return fmt.Errorf("sbz1 must be 0, is %d", sbz1)
}
// SE_SELF_RELATIVE must be set.
if (control & SE_SELF_RELATIVE) == 0 {
return fmt.Errorf("SE_SELF_RELATIVE control bit must be set (control=0x%x)", control)
}
// Caller wants us to validate DACL information?
if (flags & DACL_SECURITY_INFORMATION) != 0 {
// SE_DACL_PRESENT bit MUST be *always* set.
if (control & SE_DACL_PRESENT) == 0 {
return fmt.Errorf("SE_DACL_PRESENT control bit must always be set (control=0x%x)", control)
}
// offsetDacl may be 0 which would mean "No ACLs" aka "allow all users".
// If non-zero, OffsetDacl must point inside the relative Security Descriptor.
if offsetDacl != 0 && offsetDacl+uint32(unsafe.Sizeof(ACL{})) > uint32(len(sd)) {
return fmt.Errorf("DACL (offsetDacl=%d) must lie within sd (length=%d)", offsetDacl, len(sd))
}
}
// Caller wants us to validate SACL information?
if (flags & SACL_SECURITY_INFORMATION) != 0 {
// SE_SACL_PRESENT bit is optional. If not set it means there is no SACL present.
if (control&SE_SACL_PRESENT) != 0 && offsetSacl != 0 {
// OffsetSacl must point inside the relative Security Descriptor.
if offsetSacl+uint32(unsafe.Sizeof(ACL{})) > uint32(len(sd)) {
return fmt.Errorf("SACL (offsetSacl=%d) must lie within sd (length=%d)", offsetSacl, len(sd))
}
}
}
// Caller wants us to validate OwnerSID?
if (flags & OWNER_SECURITY_INFORMATION) != 0 {
if offsetOwner == 0 {
return fmt.Errorf("offsetOwner must not be 0")
}
// OffsetOwner must point inside the relative Security Descriptor.
if offsetOwner+uint32(unsafe.Sizeof(SID{})) > uint32(len(sd)) {
return fmt.Errorf("OwnerSID (offsetOwner=%d) must lie within sd (length=%d)",
offsetOwner, len(sd))
}
}
// Caller wants us to validate GroupSID?
if (flags & GROUP_SECURITY_INFORMATION) != 0 {
if offsetGroup == 0 {
return fmt.Errorf("offsetGroup must not be 0")
}
// OffsetGroup must point inside the relative Security Descriptor.
if offsetGroup+uint32(unsafe.Sizeof(SID{})) > uint32(len(sd)) {
return fmt.Errorf("GroupSID (offsetGroup=%d) must lie within sd (length=%d)",
offsetGroup, len(sd))
}
}
return nil
}
// sidToString returns a stringified version of a binary SID object contained in sidSlice.
// The layout of the binary SID object is as per "SID struct".
func sidToString(sidSlice []byte) (string, error) {
// Ensure we have enough bytes till SID.IdentifierAuthority.
if len(sidSlice) < 8 {
return "", fmt.Errorf("Invalid binary SID [size (%d) < 8]", len(sidSlice))
}
// SID.Revision.
revision := sidSlice[:1][0]
// SID.SubAuthorityCount.
subAuthorityCount := sidSlice[1:2][0]
// Ensure we have enough bytes for subAuthorityCount authority values, where each is a 4-byte DWORD
// in little endian format.
if len(sidSlice) < int(8+(4*subAuthorityCount)) {
return "", fmt.Errorf("Invalid binary SID [subAuthorityCount=%d, size (%d) < %d]",
subAuthorityCount, len(sidSlice), (8 + (4 * subAuthorityCount)))
}
// SID.IdentifierAuthority.
// The 48-bit authority is laid out in big endian format.
authorityHigh := uint64(binary.BigEndian.Uint16(sidSlice[2:4]))
authorityLow := uint64(binary.BigEndian.Uint32(sidSlice[4:8]))
authority := (authorityHigh<<32 | authorityLow)
sidString := fmt.Sprintf("S-%d-%d", revision, authority)
// Offset to start of SID.SubAuthority array.
offset := 8
// Parse and include all SubAuthority values in the SID string.
for i := 0; i < int(subAuthorityCount); i++ {
sidString += fmt.Sprintf("-%d", binary.LittleEndian.Uint32(sidSlice[offset:offset+4]))
offset += 4
}
return sidString, nil
}
// Return the next token (after '-' till the next '-' or end of string) from 'sidString' and the remaining
// sidString after the token.
func getNextToken(sidString string) (string /* token */, string /* remaining sidString */) {
token := ""
charsProcessed := 0
for _, c := range sidString {
charsProcessed++
if c == '-' {
break
}
token += string(c)
}
return token, sidString[charsProcessed:]
}
// stringToSid converts the string sid into a byte slice in the form of "struct SID".
// The returned byte slice can be copied to fill the sid in a binary Security Descriptor in the form of
// struct SECURITY_DESCRIPTOR_RELATIVE.
func stringToSid(sidString string) ([]byte, error) {
// Allocate a byte slice large enough to hold the binary SID.
maxSidBytes := int(unsafe.Sizeof(SID{}) + (unsafe.Sizeof(uint32(0)) * SID_MAX_SUB_AUTHORITIES))
sid := make([]byte, maxSidBytes)
sidStringOriginal := sidString
offset := 0
if (sidString[0] == 'S' || sidString[0] == 's') && sidString[1] == '-' { /* S-R-I-S-S */
// R-I-S-S.
sidString = sidString[2:]
var subAuthorityCount byte = 0
token := ""
tokenIdx := 0
for sidString != "" {
token, sidString = getNextToken(sidString)
if tokenIdx == 0 {
// SID.Revision.
revision, err := strconv.ParseUint(token, 10, 8)
if err != nil {
return nil, fmt.Errorf("stringToSid: Error parsing Revision: %v", err)
}
if revision != SID_REVISION {
return nil, fmt.Errorf("stringToSid: Invalid SID Revision %d", revision)
}
sid[0] = byte(revision)
// Increment offset by 2 as we will fill SubAuthorityCount later.
offset += 2
} else if tokenIdx == 1 {
// SID.IdentifierAuthority.
authority, err := strconv.ParseUint(token, 10, 32)
if err != nil {
return nil, fmt.Errorf("stringToSid: Error parsing IdentifierAuthority: %v", err)
}
authorityHigh := uint16(authority >> 32)
authorityLow := uint32(authority & 0xFFFFFFFF)
binary.BigEndian.PutUint16(sid[2:4], authorityHigh)
binary.BigEndian.PutUint32(sid[4:8], authorityLow)
offset += 6
} else {
// SID.SubAuthority[].
subAuth, err := strconv.ParseUint(token, 10, 32)
if err != nil {
// If not numeric, maybe domain RID, but domain RID must be the last component.
if rid, ok := domainRidShortcuts[token]; ok {
if sidString != "" {
return nil, fmt.Errorf("Domain RID (%s) seen but is not the last SubAuthority. SID=%s", token, sidStringOriginal)
}
subAuth = uint64(rid)
} else {
return nil, err
}
}
binary.LittleEndian.PutUint32(sid[offset:offset+4], uint32(subAuth))
offset += 4
subAuthorityCount++
}
tokenIdx++
}
// Now we know SubAuthorityCount, fill it.
sid[1] = subAuthorityCount
} else {
// String SID like "BA"?
if wks, ok := wellKnownSidShortcuts[sidString]; ok {
// SID.Revision.
sid[0] = wks.Revision
// SID.SubAuthorityCount.
sid[1] = wks.SubAuthorityCount
// SID.IdentifierAuthority.
copy(sid[2:8], wks.IdentifierAuthority[:])
offset = 8
for i := 0; i < int(wks.SubAuthorityCount); i++ {
// SID.SubAuthority[].
binary.LittleEndian.PutUint32(sid[offset:offset+4], wks.SubAuthority[i])
offset += 4
}
} else if rid, ok := domainRidShortcuts[sidString]; ok {
// Domain RID like "DU"?
// TODO: Add domain RID support. We need to prefix the domain SID.
fmt.Printf("Got well known RID %d\n", rid)
panic("Domain RIDs not yet implemented!")
} else {
return nil, fmt.Errorf("Invalid SID: %s", sidStringOriginal)
}
}
return sid[:offset], nil
}
// Return a string representation of the 4-byte ACE rights.
func aceRightsToString(aceRights uint32) string {
/*
* Check if the aceRights exactly maps to a shorthand name.
*/
if v, ok := aceRightsToStringMap[aceRights]; ok {
return v
}
/*
* Check if the rights can be expressed as a concatenation of shorthand names.
* Only if we can map all the OR'ed rights to shorthand names, we use it.
*/
aceRightsString := ""
var allRights uint32 = 0
for k, v := range aceRightsToStringMap {
if (aceRights & k) == k {
aceRightsString += v
allRights |= k
}
}
// Use stringified rights only if *all* available rights can be represented with a shorthand name.
// The else part is commented as it's being hit too often. One such common aceRights value is 0x1200a9.
if allRights == aceRights {
return aceRightsString
}
/*
else if allRights != 0 {
fmt.Printf("aceRightsString: Only partial rights could be stringified (aceRights=0x%x, allRights=0x%x)",
aceRights, allRights)
}
*/
// Fallback to integral mask value.
return fmt.Sprintf("0x%x", aceRights)
}
// Does the aceType correspond to an object ACE?
// We don't support object ACEs.
//nolint:deadcode,unused
func isObjectAce(aceType byte) bool {
switch aceType {
case ACCESS_ALLOWED_OBJECT_ACE_TYPE,
ACCESS_DENIED_OBJECT_ACE_TYPE,
SYSTEM_AUDIT_OBJECT_ACE_TYPE,
SYSTEM_ALARM_OBJECT_ACE_TYPE,
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE,
ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE,
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE,
SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:
return true
default:
return false
}
}
// Returns true for aceTypes that we support.
// TODO: Allow SACL ACE type, conditional ACE Types.
func isUnsupportedAceType(aceType byte) bool {
switch aceType {
case ACCESS_ALLOWED_ACE_TYPE,
ACCESS_DENIED_ACE_TYPE:
return false
default:
return true
}
}
// Convert numeric ace type to string.
func aceTypeToString(aceType BYTE) (string, error) {
for k, v := range aceTypeStringMap {
if v == aceType {
return k, nil
}
}
return "", fmt.Errorf("Unknown aceType: %d", aceType)
}
// aceToString returns a stringified version of a binary ACE object contained in aceSlice.
// The layout of the binary ACE object is as per "struct ACCESS_ALLOWED_ACE".
func aceToString(aceSlice []byte) (string, error) {
// We access 8 bytes in this function, ensure we have at least 8 bytes.
if len(aceSlice) < 8 {
return "", fmt.Errorf("Short aceSlice: %d bytes", len(aceSlice))
}
aceString := "("
// ACCESS_ALLOWED_ACE.Header.AceType.
aceType := aceSlice[:1][0]
// This is our gatekeeper for blocking unsupported ace types.
// We open up ACEs as we add support for them.
if isUnsupportedAceType(aceType) {
return "", fmt.Errorf("Unsupported ACE type: 0x%x", aceType)
}
// ACCESS_ALLOWED_ACE.Header.AceFlags.
aceFlags := aceSlice[1:2][0]
// ACCESS_ALLOWED_ACE.AccessMask.
aceRights := binary.LittleEndian.Uint32(aceSlice[4:8])
aceTypeString, err := aceTypeToString(BYTE(aceType))
if err != nil {
return "", fmt.Errorf("aceToString: %v", err)
}
aceString += aceTypeString
aceString += ";"
if (aceFlags & CONTAINER_INHERIT_ACE) != 0 {
aceString += "CI"
}
if (aceFlags & OBJECT_INHERIT_ACE) != 0 {
aceString += "OI"
}
if (aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0 {
aceString += "NP"
}
if (aceFlags & INHERIT_ONLY_ACE) != 0 {
aceString += "IO"
}
if (aceFlags & INHERITED_ACE) != 0 {
aceString += "ID"
}
if (aceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) != 0 {
aceString += "SA"
}
if (aceFlags & FAILED_ACCESS_ACE_FLAG) != 0 {
aceString += "FA"
}
if (aceType == SYSTEM_ACCESS_FILTER_ACE_TYPE) && (aceFlags&TRUST_PROTECTED_FILTER_ACE_FLAG) != 0 {
aceString += "TP"
}
if (aceFlags & CRITICAL_ACE_FLAG) != 0 {
aceString += "CR"
}
aceString += ";"
aceString += aceRightsToString(aceRights)
aceString += ";"
// TODO: Empty object_guid;inherit_object_guid.
aceString += ";"
aceString += ";"
sidoffset := 8
sidStr, err := sidToString(aceSlice[sidoffset:])
if err != nil {
return "", fmt.Errorf("aceToString: sidToString failed: %v", err)
}
aceString += sidStr
aceString += ")"
return aceString, nil
}
// Given the entrire xattr value buffer, return the SD revision.
func getRevision(sd []byte) BYTE {
if len(sd) < 1 {
return 0
}