blob: dde78614eeebad7cfa890eb2e8024c374faf9b9b [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Package pac implements Microsoft Privilege Attribute Certificate (PAC) processing.
2package pac
3
4import (
5 "bytes"
6 "fmt"
7
8 "github.com/jcmturner/rpc/v2/mstypes"
9 "github.com/jcmturner/rpc/v2/ndr"
10)
11
12// KERB_VALIDATION_INFO flags.
13const (
14 USERFLAG_GUEST = 31 // Authentication was done via the GUEST account; no password was used.
15 USERFLAG_NO_ENCRYPTION_AVAILABLE = 30 // No encryption is available.
16 USERFLAG_LAN_MANAGER_KEY = 28 // LAN Manager key was used for authentication.
17 USERFLAG_SUB_AUTH = 25 // Sub-authentication used; session key came from the sub-authentication package.
18 USERFLAG_EXTRA_SIDS = 26 // Indicates that the ExtraSids field is populated and contains additional SIDs.
19 USERFLAG_MACHINE_ACCOUNT = 24 // Indicates that the account is a machine account.
20 USERFLAG_DC_NTLM2 = 23 // Indicates that the domain controller understands NTLMv2.
21 USERFLAG_RESOURCE_GROUPIDS = 22 // Indicates that the ResourceGroupIds field is populated.
22 USERFLAG_PROFILEPATH = 21 // Indicates that ProfilePath is populated.
23 USERFLAG_NTLM2_NTCHALLENGERESP = 20 // The NTLMv2 response from the NtChallengeResponseFields ([MS-NLMP] section 2.2.1.3) was used for authentication and session key generation.
24 USERFLAG_LM2_LMCHALLENGERESP = 19 // The LMv2 response from the LmChallengeResponseFields ([MS-NLMP] section 2.2.1.3) was used for authentication and session key generation.
25 USERFLAG_AUTH_LMCHALLENGERESP_KEY_NTCHALLENGERESP = 18 // The LMv2 response from the LmChallengeResponseFields ([MS-NLMP] section 2.2.1.3) was used for authentication and the NTLMv2 response from the NtChallengeResponseFields ([MS-NLMP] section 2.2.1.3) was used session key generation.
26)
27
28// KerbValidationInfo implement https://msdn.microsoft.com/en-us/library/cc237948.aspx
29type KerbValidationInfo struct {
30 LogOnTime mstypes.FileTime
31 LogOffTime mstypes.FileTime
32 KickOffTime mstypes.FileTime
33 PasswordLastSet mstypes.FileTime
34 PasswordCanChange mstypes.FileTime
35 PasswordMustChange mstypes.FileTime
36 EffectiveName mstypes.RPCUnicodeString
37 FullName mstypes.RPCUnicodeString
38 LogonScript mstypes.RPCUnicodeString
39 ProfilePath mstypes.RPCUnicodeString
40 HomeDirectory mstypes.RPCUnicodeString
41 HomeDirectoryDrive mstypes.RPCUnicodeString
42 LogonCount uint16
43 BadPasswordCount uint16
44 UserID uint32
45 PrimaryGroupID uint32
46 GroupCount uint32
47 GroupIDs []mstypes.GroupMembership `ndr:"pointer,conformant"`
48 UserFlags uint32
49 UserSessionKey mstypes.UserSessionKey
50 LogonServer mstypes.RPCUnicodeString
51 LogonDomainName mstypes.RPCUnicodeString
52 LogonDomainID mstypes.RPCSID `ndr:"pointer"`
53 Reserved1 [2]uint32 // Has 2 elements
54 UserAccountControl uint32
55 SubAuthStatus uint32
56 LastSuccessfulILogon mstypes.FileTime
57 LastFailedILogon mstypes.FileTime
58 FailedILogonCount uint32
59 Reserved3 uint32
60 SIDCount uint32
61 ExtraSIDs []mstypes.KerbSidAndAttributes `ndr:"pointer,conformant"`
62 ResourceGroupDomainSID mstypes.RPCSID `ndr:"pointer"`
63 ResourceGroupCount uint32
64 ResourceGroupIDs []mstypes.GroupMembership `ndr:"pointer,conformant"`
65}
66
67// Unmarshal bytes into the DeviceInfo struct
68func (k *KerbValidationInfo) Unmarshal(b []byte) (err error) {
69 dec := ndr.NewDecoder(bytes.NewReader(b))
70 err = dec.Decode(k)
71 if err != nil {
72 err = fmt.Errorf("error unmarshaling KerbValidationInfo: %v", err)
73 }
74 return
75}
76
77// GetGroupMembershipSIDs returns a slice of strings containing the group membership SIDs found in the PAC.
78func (k *KerbValidationInfo) GetGroupMembershipSIDs() []string {
79 var g []string
80 lSID := k.LogonDomainID.String()
81 for i := range k.GroupIDs {
82 g = append(g, fmt.Sprintf("%s-%d", lSID, k.GroupIDs[i].RelativeID))
83 }
84 for _, s := range k.ExtraSIDs {
85 var exists = false
86 for _, es := range g {
87 if es == s.SID.String() {
88 exists = true
89 break
90 }
91 }
92 if !exists {
93 g = append(g, s.SID.String())
94 }
95 }
96 for _, r := range k.ResourceGroupIDs {
97 var exists = false
98 s := fmt.Sprintf("%s-%d", k.ResourceGroupDomainSID.String(), r.RelativeID)
99 for _, es := range g {
100 if es == s {
101 exists = true
102 break
103 }
104 }
105 if !exists {
106 g = append(g, s)
107 }
108 }
109 return g
110}