Skip to content

Commit a032811

Browse files
committed
Improvements to attributes panel behavior, deleting attribute values, Ctrl+D to pivot to the DACL, remove object from group feature, search objects by name, refactored theme.go and many bugfixes.
1 parent f9adebc commit a032811

File tree

17 files changed

+575
-385
lines changed

17 files changed

+575
-385
lines changed

README.md

Lines changed: 43 additions & 40 deletions
Large diffs are not rendered by default.

TODO.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
# TODO (priority)
22

3-
* Feature: Support deleting specific attribute values (not the entire attribute)
4-
* Feature: Modify ADIDNS dnsZones and dnsNodes
53
* Feature: Options to manipulate (edit/create/delete) gpLinks visually
6-
* Feature: Load initial cache from file
4+
* Feature: Modify ADIDNS dnsZones and dnsNodes
75

86
# TODO (later)
97

108
* Feature: Improve object creation form (implement customizations)
119
* Feature: Custom themes
1210
* Feature: Customizable keybindings
11+
* Feature: Load initial cache from file
1312
* Wish: Add tests for core functions to make sure everything is in order
1413
* Wish: Mini tool to convert godap exports into bloodhound dumps
1514
* Wish: Monitor object for real-time changes (DirSync/SyncRepl)

pkg/ldaputils/actions.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ import (
2121

2222
// Basic LDAP connection type
2323
type LDAPConn struct {
24-
Conn *ldap.Conn
25-
PagingSize uint32
26-
RootDN string
24+
Conn *ldap.Conn
25+
PagingSize uint32
26+
RootDN string
27+
DefaultRootDN string
2728
}
2829

2930
func (lc *LDAPConn) UpgradeToTLS(tlsConfig *tls.Config) error {
@@ -236,7 +237,7 @@ func (lc *LDAPConn) QueryGroupMembers(groupDN string) (group []*ldap.Entry, err
236237
ldapQuery := fmt.Sprintf("(memberOf=%s)", ldap.EscapeFilter(groupDN))
237238

238239
search := ldap.NewSearchRequest(
239-
lc.RootDN,
240+
lc.DefaultRootDN,
240241
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
241242
ldapQuery,
242243
[]string{"sAMAccountName", "objectCategory"},
@@ -273,7 +274,7 @@ func (lc *LDAPConn) QueryUserGroups(userName string) ([]*ldap.Entry, error) {
273274
samOrDn, _ := SamOrDN(userName)
274275

275276
search := ldap.NewSearchRequest(
276-
lc.RootDN,
277+
lc.DefaultRootDN,
277278
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
278279
samOrDn,
279280
[]string{"memberOf"},
@@ -496,7 +497,7 @@ func (lc *LDAPConn) GetADIDNSZones(name string, isForest bool) ([]adidns.DNSZone
496497
zoneContainer = "ForestDNSZones"
497498
}
498499

499-
queryDN := fmt.Sprintf("CN=MicrosoftDNS,DC=%s,%s", zoneContainer, lc.RootDN)
500+
queryDN := fmt.Sprintf("CN=MicrosoftDNS,DC=%s,%s", zoneContainer, lc.DefaultRootDN)
500501
queryFilter := "(objectClass=dnsZone)"
501502
if name != "" {
502503
queryFilter = fmt.Sprintf("(&%s(name=%s))", queryFilter, ldap.EscapeFilter(name))
@@ -580,7 +581,7 @@ func (lc *LDAPConn) GetADIDNSNodes(zoneDN string) ([]adidns.DNSNode, error) {
580581
records = append(records, *dnsRec)
581582
}
582583

583-
nodes = append(nodes, adidns.DNSNode{nodeDN, nodeName, records})
584+
nodes = append(nodes, adidns.DNSNode{DN: nodeDN, Name: nodeName, Records: records})
584585
}
585586

586587
return nodes, nil
@@ -679,6 +680,16 @@ func (lc *LDAPConn) DeleteAttribute(targetDN string, attributeToDelete string) e
679680
return err
680681
}
681682

683+
func (lc *LDAPConn) DeleteAttributeValues(targetDN string, targetAttribute string, valuesToDelete []string) error {
684+
var err error
685+
686+
modifyRequest := ldap.NewModifyRequest(targetDN, nil)
687+
modifyRequest.Delete(targetAttribute, valuesToDelete)
688+
689+
err = lc.Conn.Modify(modifyRequest)
690+
return err
691+
}
692+
682693
func (lc *LDAPConn) MoveObject(sourceDN string, targetDN string) error {
683694
var err error
684695

@@ -809,7 +820,7 @@ func (lc *LDAPConn) FindSIDForObject(object string) (SID string, err error) {
809820
found := false
810821
wellKnownSID := ""
811822
for key, val := range WellKnownSIDsMap {
812-
if strings.ToLower(val) == strings.ToLower(object) {
823+
if strings.EqualFold(val, object) {
813824
found = true
814825
wellKnownSID = key
815826
}
@@ -830,15 +841,15 @@ func (lc *LDAPConn) FindSIDForObject(object string) (SID string, err error) {
830841
}
831842

832843
func (lc *LDAPConn) FindSamForSID(SID string) (resolvedSID string, err error) {
833-
for entry, _ := range WellKnownSIDsMap {
844+
for entry := range WellKnownSIDsMap {
834845
if SID == entry {
835846
return WellKnownSIDsMap[entry], nil
836847
}
837848
}
838849

839850
query := fmt.Sprintf("(objectSID=%s)", SID)
840851
searchReq := ldap.NewSearchRequest(
841-
lc.RootDN,
852+
lc.DefaultRootDN,
842853
ldap.ScopeWholeSubtree, 0, 0, 0, false,
843854
query,
844855
[]string{},

pkg/ldaputils/colors.go

Lines changed: 0 additions & 86 deletions
This file was deleted.

pkg/ldaputils/formats.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func FormatLDAPAttribute(attr *ldap.EntryAttribute, timeFormat string) []string
203203
formattedEntries = []string{}
204204

205205
uacFlagKeys := make([]int, 0)
206-
for k, _ := range UacFlags {
206+
for k := range UacFlags {
207207
uacFlagKeys = append(uacFlagKeys, k)
208208
}
209209
sort.Ints(uacFlagKeys)

pkg/ldaputils/vars.go

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,28 @@ type flagDesc struct {
4949
}
5050

5151
var UacFlags = map[int]flagDesc{
52-
UAC_SCRIPT: flagDesc{"Script", ""},
53-
UAC_ACCOUNTDISABLE: flagDesc{"Disabled", "Enabled"},
54-
UAC_HOMEDIR_REQUIRED: flagDesc{"HomeDirRequired", ""},
55-
UAC_LOCKOUT: flagDesc{"LockedOut", ""},
56-
UAC_PASSWD_NOTREQD: flagDesc{"PwdNotRequired", ""},
57-
UAC_PASSWD_CANT_CHANGE: flagDesc{"CannotChangePwd", ""},
58-
UAC_ENCRYPTED_TEXT_PWD_ALLOWED: flagDesc{"EncryptedTextPwdAllowed", ""},
59-
UAC_TEMP_DUPLICATE_ACCOUNT: flagDesc{"TmpDuplicateAccount", ""},
60-
UAC_NORMAL_ACCOUNT: flagDesc{"NormalAccount", ""},
61-
UAC_INTERDOMAIN_TRUST_ACCOUNT: flagDesc{"InterdomainTrustAccount", ""},
62-
UAC_WORKSTATION_TRUST_ACCOUNT: flagDesc{"WorkstationTrustAccount", ""},
63-
UAC_SERVER_TRUST_ACCOUNT: flagDesc{"ServerTrustAccount", ""},
64-
UAC_DONT_EXPIRE_PASSWORD: flagDesc{"DoNotExpirePwd", ""},
65-
UAC_MNS_LOGON_ACCOUNT: flagDesc{"MNSLogonAccount", ""},
66-
UAC_SMARTCARD_REQUIRED: flagDesc{"SmartcardRequired", ""},
67-
UAC_TRUSTED_FOR_DELEGATION: flagDesc{"TrustedForDelegation", ""},
68-
UAC_NOT_DELEGATED: flagDesc{"NotDelegated", ""},
69-
UAC_USE_DES_KEY_ONLY: flagDesc{"UseDESKeyOnly", ""},
70-
UAC_DONT_REQ_PREAUTH: flagDesc{"DoNotRequirePreauth", ""},
71-
UAC_PASSWORD_EXPIRED: flagDesc{"PwdExpired", "PwdNotExpired"},
72-
UAC_TRUSTED_TO_AUTH_FOR_DELEGATION: flagDesc{"TrustedToAuthForDelegation", ""},
73-
UAC_PARTIAL_SECRETS_ACCOUNT: flagDesc{"PartialSecretsAccount", ""},
52+
UAC_SCRIPT: {"Script", ""},
53+
UAC_ACCOUNTDISABLE: {"Disabled", "Enabled"},
54+
UAC_HOMEDIR_REQUIRED: {"HomeDirRequired", ""},
55+
UAC_LOCKOUT: {"LockedOut", ""},
56+
UAC_PASSWD_NOTREQD: {"PwdNotRequired", ""},
57+
UAC_PASSWD_CANT_CHANGE: {"CannotChangePwd", ""},
58+
UAC_ENCRYPTED_TEXT_PWD_ALLOWED: {"EncryptedTextPwdAllowed", ""},
59+
UAC_TEMP_DUPLICATE_ACCOUNT: {"TmpDuplicateAccount", ""},
60+
UAC_NORMAL_ACCOUNT: {"NormalAccount", ""},
61+
UAC_INTERDOMAIN_TRUST_ACCOUNT: {"InterdomainTrustAccount", ""},
62+
UAC_WORKSTATION_TRUST_ACCOUNT: {"WorkstationTrustAccount", ""},
63+
UAC_SERVER_TRUST_ACCOUNT: {"ServerTrustAccount", ""},
64+
UAC_DONT_EXPIRE_PASSWORD: {"DoNotExpirePwd", ""},
65+
UAC_MNS_LOGON_ACCOUNT: {"MNSLogonAccount", ""},
66+
UAC_SMARTCARD_REQUIRED: {"SmartcardRequired", ""},
67+
UAC_TRUSTED_FOR_DELEGATION: {"TrustedForDelegation", ""},
68+
UAC_NOT_DELEGATED: {"NotDelegated", ""},
69+
UAC_USE_DES_KEY_ONLY: {"UseDESKeyOnly", ""},
70+
UAC_DONT_REQ_PREAUTH: {"DoNotRequirePreauth", ""},
71+
UAC_PASSWORD_EXPIRED: {"PwdExpired", "PwdNotExpired"},
72+
UAC_TRUSTED_TO_AUTH_FOR_DELEGATION: {"TrustedToAuthForDelegation", ""},
73+
UAC_PARTIAL_SECRETS_ACCOUNT: {"PartialSecretsAccount", ""},
7474
}
7575

7676
var SDControlFlags = map[int]string{
@@ -166,49 +166,49 @@ type LibQuery struct {
166166
}
167167

168168
var PredefinedLdapQueries = map[string][]LibQuery{
169-
"Enum": []LibQuery{
170-
LibQuery{"All Organizational Units", "(objectCategory=organizationalUnit)"},
171-
LibQuery{"All Containers", "(objectCategory=container)"},
172-
LibQuery{"All Groups", "(objectCategory=group)"},
173-
LibQuery{"All Computers", "(objectClass=computer)"},
174-
LibQuery{"All Users", "(&(objectCategory=person)(objectClass=user))"},
175-
LibQuery{"All Objects", "(objectClass=*)"},
169+
"Enum": {
170+
{"All Organizational Units", "(objectCategory=organizationalUnit)"},
171+
{"All Containers", "(objectCategory=container)"},
172+
{"All Groups", "(objectCategory=group)"},
173+
{"All Computers", "(objectClass=computer)"},
174+
{"All Users", "(&(objectCategory=person)(objectClass=user))"},
175+
{"All Objects", "(objectClass=*)"},
176176
},
177-
"Users": []LibQuery{
178-
LibQuery{"Recently Created Users", "(&(objectCategory=user)(whenCreated>=<timestamp1d>))"},
179-
LibQuery{"Users With Description", "(&(objectCategory=user)(description=*))"},
180-
LibQuery{"Users Without Email", "(&(objectCategory=user)(!(mail=*)))"},
181-
LibQuery{"Likely Service Users", "(&(objectCategory=user)(sAMAccountName=*svc*))"},
182-
LibQuery{"Disabled Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"},
183-
LibQuery{"Expired Users", "(&(objectCategory=user)(accountExpires<=<timestamp>))"},
184-
LibQuery{"Users With Sensitive Infos", "(&(objectCategory=user)(|(telephoneNumber=*)(pager=*)(homePhone=*)(mobile=*)(info=*)(streetAddress=*)))"},
185-
LibQuery{"Inactive Users", "(&(objectCategory=user)(lastLogonTimestamp<=<timestamp30d>))"},
177+
"Users": {
178+
{"Recently Created Users", "(&(objectCategory=user)(whenCreated>=<timestamp1d>))"},
179+
{"Users With Description", "(&(objectCategory=user)(description=*))"},
180+
{"Users Without Email", "(&(objectCategory=user)(!(mail=*)))"},
181+
{"Likely Service Users", "(&(objectCategory=user)(sAMAccountName=*svc*))"},
182+
{"Disabled Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"},
183+
{"Expired Users", "(&(objectCategory=user)(accountExpires<=<timestamp>))"},
184+
{"Users With Sensitive Infos", "(&(objectCategory=user)(|(telephoneNumber=*)(pager=*)(homePhone=*)(mobile=*)(info=*)(streetAddress=*)))"},
185+
{"Inactive Users", "(&(objectCategory=user)(lastLogonTimestamp<=<timestamp30d>))"},
186186
},
187-
"Computers": []LibQuery{
188-
LibQuery{"Domain Controllers", "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))"},
189-
LibQuery{"Non-DC Servers", "(&(objectCategory=computer)(operatingSystem=*server*)(!(userAccountControl:1.2.840.113556.1.4.803:=8192)))"},
190-
LibQuery{"Non-Server Computers", "(&(objectCategory=computer)(!(operatingSystem=*server*))(!(userAccountControl:1.2.840.113556.1.4.803:=8192)))"},
191-
LibQuery{"Stale Computers", "(&(objectCategory=computer)(!lastLogonTimestamp=*))"},
192-
LibQuery{"Computers With Outdated OS", "(&(objectCategory=computer)(|(operatingSystem=*Server 2008*)(operatingSystem=*Server 2003*)(operatingSystem=*Windows XP*)(operatingSystem=*Windows 7*)))"},
187+
"Computers": {
188+
{"Domain Controllers", "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))"},
189+
{"Non-DC Servers", "(&(objectCategory=computer)(operatingSystem=*server*)(!(userAccountControl:1.2.840.113556.1.4.803:=8192)))"},
190+
{"Non-Server Computers", "(&(objectCategory=computer)(!(operatingSystem=*server*))(!(userAccountControl:1.2.840.113556.1.4.803:=8192)))"},
191+
{"Stale Computers", "(&(objectCategory=computer)(!lastLogonTimestamp=*))"},
192+
{"Computers With Outdated OS", "(&(objectCategory=computer)(|(operatingSystem=*Server 2008*)(operatingSystem=*Server 2003*)(operatingSystem=*Windows XP*)(operatingSystem=*Windows 7*)))"},
193193
},
194-
"Security": []LibQuery{
195-
LibQuery{"Domain Admins", "(&(objectCategory=user)(memberOf=CN=Domain Admins,CN=Users,DC=domain,DC=com))"},
196-
LibQuery{"Administrators", "(&(objectCategory=user)(memberOf=CN=Administrators,CN=Builtin,DC=domain,DC=com))"},
197-
LibQuery{"High Privilege Users", "(&(objectCategory=user)(adminCount=1))"},
198-
LibQuery{"Users With SPN", "(&(objectCategory=user)(servicePrincipalName=*))"},
199-
LibQuery{"Users With SIDHistory", "(&(objectCategory=person)(objectClass=user)(sidHistory=*))"},
200-
LibQuery{"KrbPreauth Disabled Users", "(&(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=4194304))"},
201-
LibQuery{"KrbPreauth Disabled Computers", "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=4194304))"},
202-
LibQuery{"Constrained Delegation Objects", "(msDS-AllowedToDelegateTo=*)"},
203-
LibQuery{"Unconstrained Delegation Objects", "(userAccountControl:1.2.840.113556.1.4.803:=524288)"},
204-
LibQuery{"RBCD Objects", "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)"},
205-
LibQuery{"Not Trusted For Delegation", "(&(samaccountname=*)(userAccountControl:1.2.840.113556.1.4.803:=1048576))"},
206-
LibQuery{"Shadow Credentials Targets", "(msDS-KeyCredentialLink=*)"},
207-
LibQuery{"Must Change Password Users", "(&(objectCategory=person)(objectClass=user)(pwdLastSet=0)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2)))"},
208-
LibQuery{"Password Never Changed Users", "(&(objectCategory=user)(pwdLastSet=0))"},
209-
LibQuery{"Never Expire Password Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"},
210-
LibQuery{"Empty Password Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=32))"},
211-
LibQuery{"LockedOut Users", "(&(objectCategory=user)(lockoutTime>=1))"},
194+
"Security": {
195+
{"Domain Admins", "(&(objectCategory=user)(memberOf=CN=Domain Admins,CN=Users,DC=domain,DC=com))"},
196+
{"Administrators", "(&(objectCategory=user)(memberOf=CN=Administrators,CN=Builtin,DC=domain,DC=com))"},
197+
{"High Privilege Users", "(&(objectCategory=user)(adminCount=1))"},
198+
{"Users With SPN", "(&(objectCategory=user)(servicePrincipalName=*))"},
199+
{"Users With SIDHistory", "(&(objectCategory=person)(objectClass=user)(sidHistory=*))"},
200+
{"KrbPreauth Disabled Users", "(&(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=4194304))"},
201+
{"KrbPreauth Disabled Computers", "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=4194304))"},
202+
{"Constrained Delegation Objects", "(msDS-AllowedToDelegateTo=*)"},
203+
{"Unconstrained Delegation Objects", "(userAccountControl:1.2.840.113556.1.4.803:=524288)"},
204+
{"RBCD Objects", "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)"},
205+
{"Not Trusted For Delegation", "(&(samaccountname=*)(userAccountControl:1.2.840.113556.1.4.803:=1048576))"},
206+
{"Shadow Credentials Targets", "(msDS-KeyCredentialLink=*)"},
207+
{"Must Change Password Users", "(&(objectCategory=person)(objectClass=user)(pwdLastSet=0)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2)))"},
208+
{"Password Never Changed Users", "(&(objectCategory=user)(pwdLastSet=0))"},
209+
{"Never Expire Password Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"},
210+
{"Empty Password Users", "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=32))"},
211+
{"LockedOut Users", "(&(objectCategory=user)(lockoutTime>=1))"},
212212
},
213213
}
214214

0 commit comments

Comments
 (0)