diff --git a/modules/analyze/webservicefuncs.go b/modules/analyze/webservicefuncs.go index 3c21954..5f0aab3 100644 --- a/modules/analyze/webservicefuncs.go +++ b/modules/analyze/webservicefuncs.go @@ -223,7 +223,7 @@ func analysisfuncs(ws *webservice) { var includeobjects *engine.Objects var excludeobjects *engine.Objects - var excludequery query.Query + var excludequery query.NodeFilter // tricky tricky - if we get a call with the expanddn set, then we handle things .... differently :-) if expanddn := vars["expanddn"]; expanddn != "" { @@ -482,7 +482,7 @@ func analysisfuncs(ws *webservice) { var includeobjects *engine.Objects var excludeobjects *engine.Objects - var excludequery query.Query + var excludequery query.NodeFilter rest, includequery, err := query.ParseLDAPQuery(r.URL.Query().Get("query"), ws.Objs) if err != nil { diff --git a/modules/engine/analyzeobjects.go b/modules/engine/analyzeobjects.go index 6038eb5..308ca96 100644 --- a/modules/engine/analyzeobjects.go +++ b/modules/engine/analyzeobjects.go @@ -6,30 +6,9 @@ import ( "github.com/lkarlslund/adalanche/modules/ui" ) -var EdgeMemberOfGroup = NewEdge("MemberOfGroup") - var SortBy Attribute = NonExistingAttribute -type ProbabilityCalculatorFunction func(source, target *Object) Probability - -func (pm Edge) RegisterProbabilityCalculator(doCalc ProbabilityCalculatorFunction) Edge { - edgeInfos[pm].probability = doCalc - return pm -} - -func (pm Edge) Describe(description string) Edge { - edgeInfos[pm].Description = description - return pm -} - -func (pm Edge) Probability(source, target *Object) Probability { - if f := edgeInfos[pm].probability; f != nil { - return f(source, target) - } - - // default - return 100 -} +var EdgeMemberOfGroup = NewEdge("MemberOfGroup") // Get rid of this func NewAnalyzeObjectsOptions() AnalyzeObjectsOptions { return AnalyzeObjectsOptions{ diff --git a/modules/engine/attributes.go b/modules/engine/attributes.go index 320f19e..b9d21fd 100644 --- a/modules/engine/attributes.go +++ b/modules/engine/attributes.go @@ -82,7 +82,7 @@ var ( DownLevelLogonName = NewAttribute("downLevelLogonName").Merge() UserPrincipalName = NewAttribute("userPrincipalName").Merge() NetbiosDomain = NewAttribute("netbiosDomain").Single() // Used to merge users with - if we only have a DOMAIN\USER type of info - DomainPart = NewAttribute("domainPart").Single() + DomainContext = NewAttribute("domainContext").Single() MetaProtectedUser = NewAttribute("_protecteduser") MetaUnconstrainedDelegation = NewAttribute("_unconstraineddelegation") diff --git a/modules/engine/edge.go b/modules/engine/edge.go index 896001f..80ee055 100644 --- a/modules/engine/edge.go +++ b/modules/engine/edge.go @@ -7,6 +7,27 @@ import ( "sync" ) +type ProbabilityCalculatorFunction func(source, target *Object) Probability + +func (pm Edge) RegisterProbabilityCalculator(doCalc ProbabilityCalculatorFunction) Edge { + edgeInfos[pm].probability = doCalc + return pm +} + +func (pm Edge) Describe(description string) Edge { + edgeInfos[pm].Description = description + return pm +} + +func (pm Edge) Probability(source, target *Object) Probability { + if f := edgeInfos[pm].probability; f != nil { + return f(source, target) + } + + // default + return 100 +} + // EdgeAnalyzer takes an Object, examines it an outputs a list of Objects that can Pwn it type EdgeAnalyzer struct { ObjectAnalyzer func(o *Object, ao *Objects) diff --git a/modules/engine/objects.go b/modules/engine/objects.go index 1506724..02b8a49 100644 --- a/modules/engine/objects.go +++ b/modules/engine/objects.go @@ -702,7 +702,7 @@ func (os *Objects) FindOrAddAdjacentSID(s windowssecurity.SID, r *Object) *Objec ObjectSid, AttributeValueSID(s), DataLoader, "FindOrAddAdjacentSID", IgnoreBlanks, - DomainPart, r.Attr(DomainPart), + DomainContext, r.Attr(DomainContext), ) if !r.SID().IsNull() { if r.SID().StripRID() == s.StripRID() { @@ -710,8 +710,8 @@ func (os *Objects) FindOrAddAdjacentSID(s windowssecurity.SID, r *Object) *Objec } else { // Other domain, then it's a foreign principal no.SetFlex(ObjectCategorySimple, "Foreign-Security-Principal") - if dp := r.OneAttrString(DomainPart); dp != "" { - no.SetFlex(DistinguishedName, "CN="+s.String()+",CN=ForeignSecurityPrincipals,"+dp) + if domainContext := r.OneAttrString(DomainContext); domainContext != "" { + no.SetFlex(DistinguishedName, "CN="+s.String()+",CN=ForeignSecurityPrincipals,"+domainContext) } } } @@ -719,9 +719,9 @@ func (os *Objects) FindOrAddAdjacentSID(s windowssecurity.SID, r *Object) *Objec }) return result[0] default: - if r.HasAttr(DomainPart) { + if r.HasAttr(DomainContext) { // From outside, we need to find the domain part - if o, found := os.FindTwoMulti(ObjectSid, AttributeValueSID(s), DomainPart, r.OneAttr(DomainPart)); found { + if o, found := os.FindTwoMulti(ObjectSid, AttributeValueSID(s), DomainContext, r.OneAttr(DomainContext)); found { return o[0] } } @@ -740,7 +740,7 @@ func (os *Objects) FindOrAddAdjacentSID(s windowssecurity.SID, r *Object) *Objec if s.Component(2) != 21 { no.SetFlex( IgnoreBlanks, - DomainPart, r.Attr(DomainPart), + DomainContext, r.Attr(DomainContext), DataSource, r.Attr(DataSource), ) } @@ -750,34 +750,6 @@ func (os *Objects) FindOrAddAdjacentSID(s windowssecurity.SID, r *Object) *Objec return no } -/* -func (os *Objects) findAdjacentSID(s windowssecurity.SID, r *Object) *Object { - // These are the "local" groups shared between DCs - // We need to find the right one, and we'll use the DomainPart for this - - switch s.Component(2) { - case 21: // Full "domain" SID - return os.Find(s) - default: - if r.HasAttr(DomainPart) { - // From outside, we need to find the domain part - if o, found := os.FindTwoMulti(ObjectSid, AttributeValueSID(s), DomainPart, r.OneAttr(DomainPart)); found { - return findMostLocal(o) - } - } - // From inside same source, that is easy - if r.HasAttr(UniqueSource) { - if o, found := os.FindTwoMulti(ObjectSid, AttributeValueSID(s), UniqueSource, r.OneAttr(UniqueSource)); found { - return findMostLocal(o) - } - } - } - - // Not found - return nil -} -*/ - func findMostLocal(os []*Object) *Object { if len(os) == 0 { return nil diff --git a/modules/integrations/activedirectory/analyze/analyze-ad.go b/modules/integrations/activedirectory/analyze/analyze-ad.go index 8ffe9a1..a97f90e 100644 --- a/modules/integrations/activedirectory/analyze/analyze-ad.go +++ b/modules/integrations/activedirectory/analyze/analyze-ad.go @@ -11,7 +11,6 @@ import ( "github.com/lkarlslund/adalanche/modules/engine" "github.com/lkarlslund/adalanche/modules/integrations/activedirectory" "github.com/lkarlslund/adalanche/modules/ui" - "github.com/lkarlslund/adalanche/modules/util" "github.com/lkarlslund/adalanche/modules/windowssecurity" ) @@ -847,7 +846,7 @@ func init() { continue } - if o.HasAttr(engine.DomainPart) { + if o.HasAttr(engine.DomainContext) { continue } @@ -866,7 +865,7 @@ func init() { } if lastpart != -1 { - o.SetValues(engine.DomainPart, engine.AttributeValueString(strings.Join(parts[lastpart:], ","))) + o.SetValues(engine.DomainContext, engine.AttributeValueString(strings.Join(parts[lastpart:], ","))) } } }, @@ -879,14 +878,14 @@ func init() { return strings.HasPrefix(o.OneAttrString(engine.DistinguishedName), "CN=AdminSDHolder,CN=System,") }).Slice() { // We found it - so we know it can change ACLs of some objects - domainpart := adminsdholder.OneAttrString(engine.DomainPart) + domaincontext := adminsdholder.OneAttrString(engine.DomainContext) // Are some groups excluded? excluded_mask := 0 // Find dsHeuristics, this defines groups EXCLUDED From AdminSDHolder application // https://social.technet.microsoft.com/wiki/contents/articles/22331.adminsdholder-protected-groups-and-security-descriptor-propagator.aspx#What_is_a_protected_group - if ds, found := ao.Find(engine.DistinguishedName, engine.AttributeValueString("CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,"+domainpart)); found { + if ds, found := ao.Find(engine.DistinguishedName, engine.AttributeValueString("CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,"+domaincontext)); found { excluded := ds.OneAttrString(activedirectory.DsHeuristics) if len(excluded) >= 16 { excluded_mask = strings.Index("0123456789ABCDEF", strings.ToUpper(string(excluded[15]))) @@ -900,7 +899,7 @@ func init() { } // Only this "local" AD (for multi domain analysis) - if o.OneAttrString(engine.DomainPart) != domainpart { + if o.OneAttrString(engine.DomainContext) != domaincontext { return false } return true @@ -1005,6 +1004,7 @@ func init() { dnsroot = strings.ToLower(dnsroot) TrustMap.Store(TrustPair{ SourceNCName: ncname, + SourceDNSRoot: dnsroot, SourceNetbios: netbiosname, SourceSID: domainsid.String(), }, TrustInfo{}) @@ -1082,27 +1082,27 @@ func init() { if !found { ui.Warn().Msgf("Can not find machine object for DC %v", object.DN()) } else { - domainPart := object.OneAttr(engine.DomainPart) - if domainPart == nil { - ui.Fatal().Msgf("DomainController %v has no DomainPart attribute", object.DN()) + domainContext := object.OneAttr(engine.DomainContext) + if domainContext == nil { + ui.Fatal().Msgf("DomainController %v has no DomainContext attribute", object.DN()) } if administrators, found := ao.FindTwo(engine.ObjectSid, engine.AttributeValueSID(windowssecurity.AdministratorsSID), - engine.DomainPart, domainPart); found { + engine.DomainContext, domainContext); found { administrators.EdgeTo(machine, activedirectory.EdgeLocalAdminRights) } else { ui.Warn().Msgf("Could not find Administrators group for %v", object.DN()) } if remotedesktopusers, found := ao.FindTwo(engine.ObjectSid, engine.AttributeValueSID(windowssecurity.RemoteDesktopUsersSID), - engine.DomainPart, domainPart); found { + engine.DomainContext, domainContext); found { remotedesktopusers.EdgeTo(machine, activedirectory.EdgeLocalRDPRights) } else { ui.Warn().Msgf("Could not find Remote Desktop Users group for %v", object.DN()) } if distributeddcomusers, found := ao.FindTwo(engine.ObjectSid, engine.AttributeValueSID(windowssecurity.DCOMUsersSID), - engine.DomainPart, domainPart); found { + engine.DomainContext, domainContext); found { distributeddcomusers.EdgeTo(machine, activedirectory.EdgeLocalDCOMRights) } else { ui.Warn().Msgf("Could not find DCOM Users group for %v", object.DN()) @@ -1138,7 +1138,7 @@ func init() { TrustMap.Store(TrustPair{ SourceDNSRoot: dnsroot, - TargetDNSRoot: util.DomainSuffixToDomainPart(partner), + TargetDNSRoot: partner, }, TrustInfo{ Direction: TrustDirection(dir), }) @@ -1244,9 +1244,9 @@ func init() { } for _, o := range ao.Slice() { - if o.HasAttr(engine.ObjectSid) && o.SID().Component(2) == 21 && !o.HasAttr(engine.DistinguishedName) && o.HasAttr(engine.DomainPart) { + if o.HasAttr(engine.ObjectSid) && o.SID().Component(2) == 21 && !o.HasAttr(engine.DistinguishedName) && o.HasAttr(engine.DomainContext) { // An unknown SID, is it ours or from another domain? - ourDomainDN := o.OneAttrString(engine.DomainPart) + ourDomainDN := o.OneAttrString(engine.DomainContext) ourDomainSid, domainfound := domains[ourDomainDN] if !domainfound { continue diff --git a/modules/integrations/activedirectory/collect/cli.go b/modules/integrations/activedirectory/collect/cli.go index b7cb946..838adea 100644 --- a/modules/integrations/activedirectory/collect/cli.go +++ b/modules/integrations/activedirectory/collect/cli.go @@ -441,8 +441,7 @@ func Execute(cmd *cobra.Command, args []string) error { for _, object := range gpostocollect { // Let's check if it this is a GPO and then add som fake attributes to represent it if gpfsp, found := object.Attributes["gPCFileSysPath"]; found { - - domainPart := util.ExtractDomainPart(object.DistinguishedName) + domainContext := util.ExtractDomainContextFromDistinguishedName(object.DistinguishedName) gpodisplayname := object.Attributes["displayName"] gpoguid := object.Attributes["name"] @@ -471,7 +470,7 @@ func Execute(cmd *cobra.Command, args []string) error { gpoinfo.GPOinfo.GUID = gpuuid gpoinfo.GPOinfo.Path = originalpath // The original path is kept, we don't care - gpoinfo.GPOinfo.DomainDN = domainPart + gpoinfo.GPOinfo.DomainDN = domainContext gpoinfo.GPOinfo.DomainNetbios = netbiosname offset := len(gppath) diff --git a/modules/query/execute.go b/modules/query/execute.go index ae170e0..68f7cc0 100644 --- a/modules/query/execute.go +++ b/modules/query/execute.go @@ -13,13 +13,13 @@ type IndexSelectorInfo struct { queryIndex int } -func Execute(q Query, ao *engine.Objects) *engine.Objects { +func Execute(q NodeFilter, ao *engine.Objects) *engine.Objects { var potentialindexes []IndexSelectorInfo switch t := q.(type) { case andquery: // Iterate over all subitems for _, st := range t.subitems { - if qo, ok := st.(QueryOneAttribute); ok { + if qo, ok := st.(FilterOneAttribute); ok { if sm, ok := qo.q.(hasStringMatch); ok { // This might be in an index potentialindexes = append(potentialindexes, IndexSelectorInfo{ @@ -29,7 +29,7 @@ func Execute(q Query, ao *engine.Objects) *engine.Objects { } } } - case QueryOneAttribute: + case FilterOneAttribute: qo := t if sm, ok := qo.q.(hasStringMatch); ok { // This might be in an index diff --git a/modules/query/ldapparser.go b/modules/query/ldapparser.go index 61a1b3a..e1e9065 100644 --- a/modules/query/ldapparser.go +++ b/modules/query/ldapparser.go @@ -13,7 +13,7 @@ import ( timespan "github.com/lkarlslund/time-timespan" ) -func ParseLDAPQueryStrict(s string, ao *engine.Objects) (Query, error) { +func ParseLDAPQueryStrict(s string, ao *engine.Objects) (NodeFilter, error) { s, query, err := ParseLDAPQuery(s, ao) if err == nil && s != "" { return nil, fmt.Errorf("Extra data after query parsing: %v", s) @@ -21,12 +21,12 @@ func ParseLDAPQueryStrict(s string, ao *engine.Objects) (Query, error) { return query, err } -func ParseLDAPQuery(s string, ao *engine.Objects) (string, Query, error) { +func ParseLDAPQuery(s string, ao *engine.Objects) (string, NodeFilter, error) { qs, q, err := parseLDAPRuneQuery([]rune(s), ao) return string(qs), q, err } -func parseLDAPRuneQuery(s []rune, ao *engine.Objects) ([]rune, Query, error) { +func parseLDAPRuneQuery(s []rune, ao *engine.Objects) ([]rune, NodeFilter, error) { if len(s) < 5 { return nil, nil, errors.New("Query string too short") } @@ -35,9 +35,16 @@ func parseLDAPRuneQuery(s []rune, ao *engine.Objects) ([]rune, Query, error) { } // Strip ( s = s[1:] - var subqueries []Query - var query Query + var subqueries []NodeFilter + var query NodeFilter var err error + + var invert bool + if s[0] == '!' { + invert = true + s = s[1:] + } + switch s[0] { case '(': // double wrapped query? s, query, err = parseLDAPRuneQuery(s, ao) @@ -66,15 +73,6 @@ func parseLDAPRuneQuery(s []rune, ao *engine.Objects) ([]rune, Query, error) { } // Strip ) return s[1:], orquery{subqueries}, nil - case '!': - s, query, err = parseLDAPRuneQuery(s[1:], ao) - if err != nil { - return nil, nil, err - } - if len(s) == 0 { - return nil, nil, errors.New("Query ends with exclamation mark") - } - return s[1:], notquery{query}, err } // parse one Attribute = Value pair @@ -224,7 +222,7 @@ valueloop: return s, &random100{comparator, valuenum}, nil case "_pwnable", "_canpwn", "out", "in": edgename := value - var target Query + var target NodeFilter commapos := strings.Index(edgename, ",") if commapos != -1 { edgename = value[:commapos] @@ -266,39 +264,41 @@ valueloop: var casesensitive bool - var genwrapper func(aq QueryAttribute) Query + var genwrapper func(aq FilterAttribute) NodeFilter switch len(attributes) { case 0: - genwrapper = func(aq QueryAttribute) Query { - return QueryAnyAttribute{aq} + genwrapper = func(aq FilterAttribute) NodeFilter { + return FilterAnyAttribute{aq} } case 1: - genwrapper = func(aq QueryAttribute) Query { - return QueryOneAttribute{attributes[0], aq} + genwrapper = func(aq FilterAttribute) NodeFilter { + return FilterOneAttribute{attributes[0], aq} } default: - genwrapper = func(aq QueryAttribute) Query { - return QueryMultipleAttributes{attributename, attributes, aq} + genwrapper = func(aq FilterAttribute) NodeFilter { + return FilterMultipleAttributes{attributename, attributes, aq} } } + var result NodeFilter + // Decide what to do switch modifier { case "": - // That's OK, this is default :-) + // That's OK, this is default :-) - continue below case "caseExactMatch": casesensitive = true case "count": if numok != nil { return nil, nil, errors.New("Could not convert value to integer for modifier comparison") } - return s, genwrapper(countModifier{comparator, valuenum}), nil + result = genwrapper(countModifier{comparator, valuenum}) case "len", "length": if numok != nil { return nil, nil, errors.New("Could not convert value to integer for modifier comparison") } - return s, genwrapper(lengthModifier{comparator, valuenum}), nil + result = genwrapper(lengthModifier{comparator, valuenum}) case "since": if numok != nil { // try to parse it as an duration @@ -306,13 +306,14 @@ valueloop: if err != nil { return nil, nil, errors.New("Could not parse value as a duration (5h2m)") } - return s, genwrapper(sinceModifier{comparator, duration}), nil + result = genwrapper(sinceModifier{comparator, duration}) + break } duration, err := timespan.ParseTimespan(fmt.Sprintf("%vs", valuenum)) if err != nil { return nil, nil, errors.New("Could not parse value as a duration of seconds (5h2m)") } - return s, genwrapper(sinceModifier{comparator, duration}), nil + result = genwrapper(sinceModifier{comparator, duration}) case "timediff": if attribute2 == engine.NonExistingAttribute { return nil, nil, errors.New("timediff modifier requires two attributes") @@ -323,75 +324,84 @@ valueloop: if err != nil { return nil, nil, errors.New("Could not parse value as a duration (5h2m)") } - return s, genwrapper(timediffModifier{attribute2, comparator, duration}), nil + result = genwrapper(timediffModifier{attribute2, comparator, duration}) + break } duration, err := timespan.ParseTimespan(fmt.Sprintf("%vs", valuenum)) if err != nil { return nil, nil, errors.New("Could not parse value as a duration of seconds (5h2m)") } - return s, genwrapper(timediffModifier{attribute2, comparator, duration}), nil - + result = genwrapper(timediffModifier{attribute2, comparator, duration}) case "1.2.840.113556.1.4.803", "and": if comparator != CompareEquals { return nil, nil, errors.New("Modifier 1.2.840.113556.1.4.803 requires equality comparator") } - return s, genwrapper(andModifier{valuenum}), nil + result = genwrapper(andModifier{valuenum}) case "1.2.840.113556.1.4.804", "or": if comparator != CompareEquals { return nil, nil, errors.New("Modifier 1.2.840.113556.1.4.804 requires equality comparator") } - return s, genwrapper(orModifier{valuenum}), nil + result = genwrapper(orModifier{valuenum}) case "1.2.840.113556.1.4.1941", "dnchain": // Matching rule in chain - return s, genwrapper(recursiveDNmatcher{value, ao}), nil + result = genwrapper(recursiveDNmatcher{value, ao}) default: return nil, nil, errors.New("Unknown modifier " + modifier) } - // string comparison - if comparator == CompareEquals { - if value == "*" { - return s, genwrapper(hasAttr{}), nil - } - if strings.HasPrefix(value, "/") && strings.HasSuffix(value, "/") { - // regexp magic - pattern := value[1 : len(value)-1] - r, err := regexp.Compile(pattern) - if err != nil { - return nil, nil, err + if result == nil { + // string comparison + if comparator == CompareEquals { + if value == "*" { + result = genwrapper(hasAttr{}) + } else if strings.HasPrefix(value, "/") && strings.HasSuffix(value, "/") { + // regexp magic + pattern := value[1 : len(value)-1] + r, err := regexp.Compile(pattern) + if err != nil { + return nil, nil, err + } + result = genwrapper(hasRegexpMatch{r}) + } else if strings.ContainsAny(value, "?*") { + // glob magic + pattern := value + if !casesensitive { + pattern = strings.ToLower(pattern) + } + g, err := glob.Compile(pattern) + if err != nil { + return nil, nil, err + } + if casesensitive { + result = genwrapper(hasGlobMatch{true, pattern, g}) + } else { + result = genwrapper(hasGlobMatch{false, pattern, g}) + } + } else { + result = genwrapper(hasStringMatch{casesensitive, value}) } - return s, genwrapper(hasRegexpMatch{r}), nil } - if strings.ContainsAny(value, "?*") { - // glob magic - pattern := value - if !casesensitive { - pattern = strings.ToLower(pattern) - } - g, err := glob.Compile(pattern) - if err != nil { - return nil, nil, err - } - if casesensitive { - return s, genwrapper(hasGlobMatch{true, pattern, g}), nil - } - return s, genwrapper(hasGlobMatch{false, pattern, g}), nil + } + + if result == nil { + // the other comparators require numeric value + if numok != nil { + return nil, nil, fmt.Errorf("Could not convert value %v to integer for numeric comparison", value) } - return s, genwrapper(hasStringMatch{casesensitive, value}), nil + result = genwrapper(numericComparator{comparator, valuenum}) } - // the other comparators require numeric value - if numok != nil { - return nil, nil, fmt.Errorf("Could not convert value %v to integer for numeric comparison", value) + if invert { + result = notquery{result} } - return s, genwrapper(numericComparator{comparator, valuenum}), nil + return s, result, nil } -func parseMultipleLDAPRuneQueries(s []rune, ao *engine.Objects) ([]rune, []Query, error) { - var result []Query +func parseMultipleLDAPRuneQueries(s []rune, ao *engine.Objects) ([]rune, []NodeFilter, error) { + var result []NodeFilter for len(s) > 0 && s[0] == '(' { - var query Query + var query NodeFilter var err error s, query, err = parseLDAPRuneQuery(s, ao) if err != nil { diff --git a/modules/query/types.go b/modules/query/types.go index 9eb7143..dbbeb3b 100644 --- a/modules/query/types.go +++ b/modules/query/types.go @@ -13,38 +13,38 @@ import ( timespan "github.com/lkarlslund/time-timespan" ) -type Query interface { +type NodeFilter interface { Evaluate(o *engine.Object) bool ToLDAPFilter() string ToWhereClause() string } // Wraps one Attribute around a queryattribute interface -type QueryOneAttribute struct { +type FilterOneAttribute struct { a engine.Attribute - q QueryAttribute + q FilterAttribute } -func (qoa QueryOneAttribute) Evaluate(o *engine.Object) bool { +func (qoa FilterOneAttribute) Evaluate(o *engine.Object) bool { return qoa.q.Evaluate(qoa.a, o) } -func (qoa QueryOneAttribute) ToLDAPFilter() string { +func (qoa FilterOneAttribute) ToLDAPFilter() string { return qoa.q.ToLDAPFilter(qoa.a.String()) } -func (qoa QueryOneAttribute) ToWhereClause() string { +func (qoa FilterOneAttribute) ToWhereClause() string { return qoa.q.ToWhereClause(qoa.a.String()) } // Wraps one Attribute around a queryattribute interface -type QueryMultipleAttributes struct { +type FilterMultipleAttributes struct { attrglobstr string a []engine.Attribute - q QueryAttribute + q FilterAttribute } -func (qma QueryMultipleAttributes) Evaluate(o *engine.Object) bool { +func (qma FilterMultipleAttributes) Evaluate(o *engine.Object) bool { for _, a := range qma.a { if qma.q.Evaluate(a, o) { return true @@ -53,20 +53,20 @@ func (qma QueryMultipleAttributes) Evaluate(o *engine.Object) bool { return false } -func (qma QueryMultipleAttributes) ToLDAPFilter() string { +func (qma FilterMultipleAttributes) ToLDAPFilter() string { return qma.q.ToLDAPFilter(qma.attrglobstr) } -func (qma QueryMultipleAttributes) ToWhereClause() string { +func (qma FilterMultipleAttributes) ToWhereClause() string { return qma.q.ToWhereClause(qma.attrglobstr) } // Wraps any attribute around a queryattribute interface -type QueryAnyAttribute struct { - q QueryAttribute +type FilterAnyAttribute struct { + q FilterAttribute } -func (qaa QueryAnyAttribute) Evaluate(o *engine.Object) bool { +func (qaa FilterAnyAttribute) Evaluate(o *engine.Object) bool { var result bool o.AttrIterator(func(attr engine.Attribute, avs engine.AttributeValues) bool { if qaa.q.Evaluate(attr, o) { @@ -78,27 +78,27 @@ func (qaa QueryAnyAttribute) Evaluate(o *engine.Object) bool { return result } -func (qaa QueryAnyAttribute) ToLDAPFilter() string { +func (qaa FilterAnyAttribute) ToLDAPFilter() string { return "*" + qaa.q.ToLDAPFilter("*") } -func (qaa QueryAnyAttribute) ToWhereClause() string { +func (qaa FilterAnyAttribute) ToWhereClause() string { return "*" + qaa.q.ToWhereClause("*") } -type QueryAttribute interface { +type FilterAttribute interface { Evaluate(a engine.Attribute, o *engine.Object) bool ToLDAPFilter(a string) string ToWhereClause(a string) string } -type ObjectStrings interface { - Strings(o *engine.Object) []string -} +// type ObjectStrings interface { +// Strings(o *engine.Object) []string +// } -type ObjectInt interface { - Int(o *engine.Object) (int64, bool) -} +// type ObjectInt interface { +// Int(o *engine.Object) (int64, bool) +// } type comparatortype byte @@ -157,7 +157,7 @@ func (a LowerStringAttribute) Strings(o *engine.Object) []string { } type andquery struct { - subitems []Query + subitems []NodeFilter } func (q andquery) Evaluate(o *engine.Object) bool { @@ -189,7 +189,7 @@ func (q andquery) ToWhereClause() string { } type orquery struct { - subitems []Query + subitems []NodeFilter } func (q orquery) Evaluate(o *engine.Object) bool { @@ -222,7 +222,7 @@ func (q orquery) ToWhereClause() string { } type notquery struct { - subitem Query + subitem NodeFilter } func (q notquery) Evaluate(o *engine.Object) bool { @@ -644,7 +644,7 @@ func recursiveDNmatchFunc(o *engine.Object, a engine.Attribute, dn string, maxde type pwnquery struct { direction engine.EdgeDirection method engine.Edge - target Query + target NodeFilter } func (p pwnquery) Evaluate(o *engine.Object) bool { diff --git a/modules/util/util.go b/modules/util/util.go index ba00545..ef2987f 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -122,7 +122,7 @@ func ExtractNetbiosFromBase(dn string) string { return netbios } -func ExtractDomainPart(dn string) string { +func ExtractDomainContextFromDistinguishedName(dn string) string { elements := strings.Split(dn, ",") last := len(elements) first := last // assume we have nothing @@ -138,7 +138,16 @@ func ExtractDomainPart(dn string) string { return strings.ToLower(strings.Join(elements[first:last], ",")) } -func DomainSuffixToDomainPart(domain string) string { +func DomainContextToDomainSuffix(dn string) string { + elements := strings.Split(dn, ",") + for i, element := range elements { + elements[i] = strings.TrimPrefix(strings.ToLower(element), "dc=") + } + + return strings.Join(elements, ".") +} + +func DomainSuffixToDomainContext(domain string) string { parts := strings.Split(domain, ".") return strings.ToLower("dc=" + strings.Join(parts, ",dc=")) }