filter.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ldap
  5. import (
  6. "bytes"
  7. hexpac "encoding/hex"
  8. "errors"
  9. "fmt"
  10. "strings"
  11. "unicode/utf8"
  12. "gopkg.in/asn1-ber.v1"
  13. )
  14. // Filter choices
  15. const (
  16. FilterAnd = 0
  17. FilterOr = 1
  18. FilterNot = 2
  19. FilterEqualityMatch = 3
  20. FilterSubstrings = 4
  21. FilterGreaterOrEqual = 5
  22. FilterLessOrEqual = 6
  23. FilterPresent = 7
  24. FilterApproxMatch = 8
  25. FilterExtensibleMatch = 9
  26. )
  27. // FilterMap contains human readable descriptions of Filter choices
  28. var FilterMap = map[uint64]string{
  29. FilterAnd: "And",
  30. FilterOr: "Or",
  31. FilterNot: "Not",
  32. FilterEqualityMatch: "Equality Match",
  33. FilterSubstrings: "Substrings",
  34. FilterGreaterOrEqual: "Greater Or Equal",
  35. FilterLessOrEqual: "Less Or Equal",
  36. FilterPresent: "Present",
  37. FilterApproxMatch: "Approx Match",
  38. FilterExtensibleMatch: "Extensible Match",
  39. }
  40. // SubstringFilter options
  41. const (
  42. FilterSubstringsInitial = 0
  43. FilterSubstringsAny = 1
  44. FilterSubstringsFinal = 2
  45. )
  46. // FilterSubstringsMap contains human readable descriptions of SubstringFilter choices
  47. var FilterSubstringsMap = map[uint64]string{
  48. FilterSubstringsInitial: "Substrings Initial",
  49. FilterSubstringsAny: "Substrings Any",
  50. FilterSubstringsFinal: "Substrings Final",
  51. }
  52. // MatchingRuleAssertion choices
  53. const (
  54. MatchingRuleAssertionMatchingRule = 1
  55. MatchingRuleAssertionType = 2
  56. MatchingRuleAssertionMatchValue = 3
  57. MatchingRuleAssertionDNAttributes = 4
  58. )
  59. // MatchingRuleAssertionMap contains human readable descriptions of MatchingRuleAssertion choices
  60. var MatchingRuleAssertionMap = map[uint64]string{
  61. MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule",
  62. MatchingRuleAssertionType: "Matching Rule Assertion Type",
  63. MatchingRuleAssertionMatchValue: "Matching Rule Assertion Match Value",
  64. MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes",
  65. }
  66. // CompileFilter converts a string representation of a filter into a BER-encoded packet
  67. func CompileFilter(filter string) (*ber.Packet, error) {
  68. if len(filter) == 0 || filter[0] != '(' {
  69. return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('"))
  70. }
  71. packet, pos, err := compileFilter(filter, 1)
  72. if err != nil {
  73. return nil, err
  74. }
  75. if pos != len(filter) {
  76. return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
  77. }
  78. return packet, nil
  79. }
  80. // DecompileFilter converts a packet representation of a filter into a string representation
  81. func DecompileFilter(packet *ber.Packet) (ret string, err error) {
  82. defer func() {
  83. if r := recover(); r != nil {
  84. err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
  85. }
  86. }()
  87. ret = "("
  88. err = nil
  89. childStr := ""
  90. switch packet.Tag {
  91. case FilterAnd:
  92. ret += "&"
  93. for _, child := range packet.Children {
  94. childStr, err = DecompileFilter(child)
  95. if err != nil {
  96. return
  97. }
  98. ret += childStr
  99. }
  100. case FilterOr:
  101. ret += "|"
  102. for _, child := range packet.Children {
  103. childStr, err = DecompileFilter(child)
  104. if err != nil {
  105. return
  106. }
  107. ret += childStr
  108. }
  109. case FilterNot:
  110. ret += "!"
  111. childStr, err = DecompileFilter(packet.Children[0])
  112. if err != nil {
  113. return
  114. }
  115. ret += childStr
  116. case FilterSubstrings:
  117. ret += ber.DecodeString(packet.Children[0].Data.Bytes())
  118. ret += "="
  119. for i, child := range packet.Children[1].Children {
  120. if i == 0 && child.Tag != FilterSubstringsInitial {
  121. ret += "*"
  122. }
  123. ret += EscapeFilter(ber.DecodeString(child.Data.Bytes()))
  124. if child.Tag != FilterSubstringsFinal {
  125. ret += "*"
  126. }
  127. }
  128. case FilterEqualityMatch:
  129. ret += ber.DecodeString(packet.Children[0].Data.Bytes())
  130. ret += "="
  131. ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
  132. case FilterGreaterOrEqual:
  133. ret += ber.DecodeString(packet.Children[0].Data.Bytes())
  134. ret += ">="
  135. ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
  136. case FilterLessOrEqual:
  137. ret += ber.DecodeString(packet.Children[0].Data.Bytes())
  138. ret += "<="
  139. ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
  140. case FilterPresent:
  141. ret += ber.DecodeString(packet.Data.Bytes())
  142. ret += "=*"
  143. case FilterApproxMatch:
  144. ret += ber.DecodeString(packet.Children[0].Data.Bytes())
  145. ret += "~="
  146. ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
  147. case FilterExtensibleMatch:
  148. attr := ""
  149. dnAttributes := false
  150. matchingRule := ""
  151. value := ""
  152. for _, child := range packet.Children {
  153. switch child.Tag {
  154. case MatchingRuleAssertionMatchingRule:
  155. matchingRule = ber.DecodeString(child.Data.Bytes())
  156. case MatchingRuleAssertionType:
  157. attr = ber.DecodeString(child.Data.Bytes())
  158. case MatchingRuleAssertionMatchValue:
  159. value = ber.DecodeString(child.Data.Bytes())
  160. case MatchingRuleAssertionDNAttributes:
  161. dnAttributes = child.Value.(bool)
  162. }
  163. }
  164. if len(attr) > 0 {
  165. ret += attr
  166. }
  167. if dnAttributes {
  168. ret += ":dn"
  169. }
  170. if len(matchingRule) > 0 {
  171. ret += ":"
  172. ret += matchingRule
  173. }
  174. ret += ":="
  175. ret += EscapeFilter(value)
  176. }
  177. ret += ")"
  178. return
  179. }
  180. func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) {
  181. for pos < len(filter) && filter[pos] == '(' {
  182. child, newPos, err := compileFilter(filter, pos+1)
  183. if err != nil {
  184. return pos, err
  185. }
  186. pos = newPos
  187. parent.AppendChild(child)
  188. }
  189. if pos == len(filter) {
  190. return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
  191. }
  192. return pos + 1, nil
  193. }
  194. func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
  195. var (
  196. packet *ber.Packet
  197. err error
  198. )
  199. defer func() {
  200. if r := recover(); r != nil {
  201. err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter"))
  202. }
  203. }()
  204. newPos := pos
  205. currentRune, currentWidth := utf8.DecodeRuneInString(filter[newPos:])
  206. switch currentRune {
  207. case utf8.RuneError:
  208. return nil, 0, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
  209. case '(':
  210. packet, newPos, err = compileFilter(filter, pos+currentWidth)
  211. newPos++
  212. return packet, newPos, err
  213. case '&':
  214. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd])
  215. newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
  216. return packet, newPos, err
  217. case '|':
  218. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr])
  219. newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
  220. return packet, newPos, err
  221. case '!':
  222. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot])
  223. var child *ber.Packet
  224. child, newPos, err = compileFilter(filter, pos+currentWidth)
  225. packet.AppendChild(child)
  226. return packet, newPos, err
  227. default:
  228. const (
  229. stateReadingAttr = 0
  230. stateReadingExtensibleMatchingRule = 1
  231. stateReadingCondition = 2
  232. )
  233. state := stateReadingAttr
  234. attribute := ""
  235. extensibleDNAttributes := false
  236. extensibleMatchingRule := ""
  237. condition := ""
  238. for newPos < len(filter) {
  239. remainingFilter := filter[newPos:]
  240. currentRune, currentWidth = utf8.DecodeRuneInString(remainingFilter)
  241. if currentRune == ')' {
  242. break
  243. }
  244. if currentRune == utf8.RuneError {
  245. return packet, newPos, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
  246. }
  247. switch state {
  248. case stateReadingAttr:
  249. switch {
  250. // Extensible rule, with only DN-matching
  251. case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:="):
  252. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
  253. extensibleDNAttributes = true
  254. state = stateReadingCondition
  255. newPos += 5
  256. // Extensible rule, with DN-matching and a matching OID
  257. case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:"):
  258. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
  259. extensibleDNAttributes = true
  260. state = stateReadingExtensibleMatchingRule
  261. newPos += 4
  262. // Extensible rule, with attr only
  263. case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
  264. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
  265. state = stateReadingCondition
  266. newPos += 2
  267. // Extensible rule, with no DN attribute matching
  268. case currentRune == ':':
  269. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
  270. state = stateReadingExtensibleMatchingRule
  271. newPos++
  272. // Equality condition
  273. case currentRune == '=':
  274. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch])
  275. state = stateReadingCondition
  276. newPos++
  277. // Greater-than or equal
  278. case currentRune == '>' && strings.HasPrefix(remainingFilter, ">="):
  279. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual])
  280. state = stateReadingCondition
  281. newPos += 2
  282. // Less-than or equal
  283. case currentRune == '<' && strings.HasPrefix(remainingFilter, "<="):
  284. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual])
  285. state = stateReadingCondition
  286. newPos += 2
  287. // Approx
  288. case currentRune == '~' && strings.HasPrefix(remainingFilter, "~="):
  289. packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterApproxMatch])
  290. state = stateReadingCondition
  291. newPos += 2
  292. // Still reading the attribute name
  293. default:
  294. attribute += fmt.Sprintf("%c", currentRune)
  295. newPos += currentWidth
  296. }
  297. case stateReadingExtensibleMatchingRule:
  298. switch {
  299. // Matching rule OID is done
  300. case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
  301. state = stateReadingCondition
  302. newPos += 2
  303. // Still reading the matching rule oid
  304. default:
  305. extensibleMatchingRule += fmt.Sprintf("%c", currentRune)
  306. newPos += currentWidth
  307. }
  308. case stateReadingCondition:
  309. // append to the condition
  310. condition += fmt.Sprintf("%c", currentRune)
  311. newPos += currentWidth
  312. }
  313. }
  314. if newPos == len(filter) {
  315. err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
  316. return packet, newPos, err
  317. }
  318. if packet == nil {
  319. err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter"))
  320. return packet, newPos, err
  321. }
  322. switch {
  323. case packet.Tag == FilterExtensibleMatch:
  324. // MatchingRuleAssertion ::= SEQUENCE {
  325. // matchingRule [1] MatchingRuleID OPTIONAL,
  326. // type [2] AttributeDescription OPTIONAL,
  327. // matchValue [3] AssertionValue,
  328. // dnAttributes [4] BOOLEAN DEFAULT FALSE
  329. // }
  330. // Include the matching rule oid, if specified
  331. if len(extensibleMatchingRule) > 0 {
  332. packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule, MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule]))
  333. }
  334. // Include the attribute, if specified
  335. if len(attribute) > 0 {
  336. packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute, MatchingRuleAssertionMap[MatchingRuleAssertionType]))
  337. }
  338. // Add the value (only required child)
  339. encodedString, encodeErr := escapedStringToEncodedBytes(condition)
  340. if encodeErr != nil {
  341. return packet, newPos, encodeErr
  342. }
  343. packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchValue, encodedString, MatchingRuleAssertionMap[MatchingRuleAssertionMatchValue]))
  344. // Defaults to false, so only include in the sequence if true
  345. if extensibleDNAttributes {
  346. packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes]))
  347. }
  348. case packet.Tag == FilterEqualityMatch && condition == "*":
  349. packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute, FilterMap[FilterPresent])
  350. case packet.Tag == FilterEqualityMatch && strings.Contains(condition, "*"):
  351. packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
  352. packet.Tag = FilterSubstrings
  353. packet.Description = FilterMap[uint64(packet.Tag)]
  354. seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
  355. parts := strings.Split(condition, "*")
  356. for i, part := range parts {
  357. if part == "" {
  358. continue
  359. }
  360. var tag ber.Tag
  361. switch i {
  362. case 0:
  363. tag = FilterSubstringsInitial
  364. case len(parts) - 1:
  365. tag = FilterSubstringsFinal
  366. default:
  367. tag = FilterSubstringsAny
  368. }
  369. encodedString, encodeErr := escapedStringToEncodedBytes(part)
  370. if encodeErr != nil {
  371. return packet, newPos, encodeErr
  372. }
  373. seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, tag, encodedString, FilterSubstringsMap[uint64(tag)]))
  374. }
  375. packet.AppendChild(seq)
  376. default:
  377. encodedString, encodeErr := escapedStringToEncodedBytes(condition)
  378. if encodeErr != nil {
  379. return packet, newPos, encodeErr
  380. }
  381. packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
  382. packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition"))
  383. }
  384. newPos += currentWidth
  385. return packet, newPos, err
  386. }
  387. }
  388. // Convert from "ABC\xx\xx\xx" form to literal bytes for transport
  389. func escapedStringToEncodedBytes(escapedString string) (string, error) {
  390. var buffer bytes.Buffer
  391. i := 0
  392. for i < len(escapedString) {
  393. currentRune, currentWidth := utf8.DecodeRuneInString(escapedString[i:])
  394. if currentRune == utf8.RuneError {
  395. return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", i))
  396. }
  397. // Check for escaped hex characters and convert them to their literal value for transport.
  398. if currentRune == '\\' {
  399. // http://tools.ietf.org/search/rfc4515
  400. // \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not
  401. // being a member of UTF1SUBSET.
  402. if i+2 > len(escapedString) {
  403. return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter"))
  404. }
  405. escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3])
  406. if decodeErr != nil {
  407. return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter"))
  408. }
  409. buffer.WriteByte(escByte[0])
  410. i += 2 // +1 from end of loop, so 3 total for \xx.
  411. } else {
  412. buffer.WriteRune(currentRune)
  413. }
  414. i += currentWidth
  415. }
  416. return buffer.String(), nil
  417. }