ldap.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. "errors"
  7. "io/ioutil"
  8. "os"
  9. ber "gopkg.in/asn1-ber.v1"
  10. )
  11. // LDAP Application Codes
  12. const (
  13. ApplicationBindRequest = 0
  14. ApplicationBindResponse = 1
  15. ApplicationUnbindRequest = 2
  16. ApplicationSearchRequest = 3
  17. ApplicationSearchResultEntry = 4
  18. ApplicationSearchResultDone = 5
  19. ApplicationModifyRequest = 6
  20. ApplicationModifyResponse = 7
  21. ApplicationAddRequest = 8
  22. ApplicationAddResponse = 9
  23. ApplicationDelRequest = 10
  24. ApplicationDelResponse = 11
  25. ApplicationModifyDNRequest = 12
  26. ApplicationModifyDNResponse = 13
  27. ApplicationCompareRequest = 14
  28. ApplicationCompareResponse = 15
  29. ApplicationAbandonRequest = 16
  30. ApplicationSearchResultReference = 19
  31. ApplicationExtendedRequest = 23
  32. ApplicationExtendedResponse = 24
  33. )
  34. var ApplicationMap = map[uint8]string{
  35. ApplicationBindRequest: "Bind Request",
  36. ApplicationBindResponse: "Bind Response",
  37. ApplicationUnbindRequest: "Unbind Request",
  38. ApplicationSearchRequest: "Search Request",
  39. ApplicationSearchResultEntry: "Search Result Entry",
  40. ApplicationSearchResultDone: "Search Result Done",
  41. ApplicationModifyRequest: "Modify Request",
  42. ApplicationModifyResponse: "Modify Response",
  43. ApplicationAddRequest: "Add Request",
  44. ApplicationAddResponse: "Add Response",
  45. ApplicationDelRequest: "Del Request",
  46. ApplicationDelResponse: "Del Response",
  47. ApplicationModifyDNRequest: "Modify DN Request",
  48. ApplicationModifyDNResponse: "Modify DN Response",
  49. ApplicationCompareRequest: "Compare Request",
  50. ApplicationCompareResponse: "Compare Response",
  51. ApplicationAbandonRequest: "Abandon Request",
  52. ApplicationSearchResultReference: "Search Result Reference",
  53. ApplicationExtendedRequest: "Extended Request",
  54. ApplicationExtendedResponse: "Extended Response",
  55. }
  56. // Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)
  57. const (
  58. BeheraPasswordExpired = 0
  59. BeheraAccountLocked = 1
  60. BeheraChangeAfterReset = 2
  61. BeheraPasswordModNotAllowed = 3
  62. BeheraMustSupplyOldPassword = 4
  63. BeheraInsufficientPasswordQuality = 5
  64. BeheraPasswordTooShort = 6
  65. BeheraPasswordTooYoung = 7
  66. BeheraPasswordInHistory = 8
  67. )
  68. var BeheraPasswordPolicyErrorMap = map[int8]string{
  69. BeheraPasswordExpired: "Password expired",
  70. BeheraAccountLocked: "Account locked",
  71. BeheraChangeAfterReset: "Password must be changed",
  72. BeheraPasswordModNotAllowed: "Policy prevents password modification",
  73. BeheraMustSupplyOldPassword: "Policy requires old password in order to change password",
  74. BeheraInsufficientPasswordQuality: "Password fails quality checks",
  75. BeheraPasswordTooShort: "Password is too short for policy",
  76. BeheraPasswordTooYoung: "Password has been changed too recently",
  77. BeheraPasswordInHistory: "New password is in list of old passwords",
  78. }
  79. // Adds descriptions to an LDAP Response packet for debugging
  80. func addLDAPDescriptions(packet *ber.Packet) (err error) {
  81. defer func() {
  82. if r := recover(); r != nil {
  83. err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions"))
  84. }
  85. }()
  86. packet.Description = "LDAP Response"
  87. packet.Children[0].Description = "Message ID"
  88. application := uint8(packet.Children[1].Tag)
  89. packet.Children[1].Description = ApplicationMap[application]
  90. switch application {
  91. case ApplicationBindRequest:
  92. addRequestDescriptions(packet)
  93. case ApplicationBindResponse:
  94. addDefaultLDAPResponseDescriptions(packet)
  95. case ApplicationUnbindRequest:
  96. addRequestDescriptions(packet)
  97. case ApplicationSearchRequest:
  98. addRequestDescriptions(packet)
  99. case ApplicationSearchResultEntry:
  100. packet.Children[1].Children[0].Description = "Object Name"
  101. packet.Children[1].Children[1].Description = "Attributes"
  102. for _, child := range packet.Children[1].Children[1].Children {
  103. child.Description = "Attribute"
  104. child.Children[0].Description = "Attribute Name"
  105. child.Children[1].Description = "Attribute Values"
  106. for _, grandchild := range child.Children[1].Children {
  107. grandchild.Description = "Attribute Value"
  108. }
  109. }
  110. if len(packet.Children) == 3 {
  111. addControlDescriptions(packet.Children[2])
  112. }
  113. case ApplicationSearchResultDone:
  114. addDefaultLDAPResponseDescriptions(packet)
  115. case ApplicationModifyRequest:
  116. addRequestDescriptions(packet)
  117. case ApplicationModifyResponse:
  118. case ApplicationAddRequest:
  119. addRequestDescriptions(packet)
  120. case ApplicationAddResponse:
  121. case ApplicationDelRequest:
  122. addRequestDescriptions(packet)
  123. case ApplicationDelResponse:
  124. case ApplicationModifyDNRequest:
  125. addRequestDescriptions(packet)
  126. case ApplicationModifyDNResponse:
  127. case ApplicationCompareRequest:
  128. addRequestDescriptions(packet)
  129. case ApplicationCompareResponse:
  130. case ApplicationAbandonRequest:
  131. addRequestDescriptions(packet)
  132. case ApplicationSearchResultReference:
  133. case ApplicationExtendedRequest:
  134. addRequestDescriptions(packet)
  135. case ApplicationExtendedResponse:
  136. }
  137. return nil
  138. }
  139. func addControlDescriptions(packet *ber.Packet) {
  140. packet.Description = "Controls"
  141. for _, child := range packet.Children {
  142. child.Description = "Control"
  143. child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
  144. value := child.Children[1]
  145. if len(child.Children) == 3 {
  146. child.Children[1].Description = "Criticality"
  147. value = child.Children[2]
  148. }
  149. value.Description = "Control Value"
  150. switch child.Children[0].Value.(string) {
  151. case ControlTypePaging:
  152. value.Description += " (Paging)"
  153. if value.Value != nil {
  154. valueChildren := ber.DecodePacket(value.Data.Bytes())
  155. value.Data.Truncate(0)
  156. value.Value = nil
  157. valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
  158. value.AppendChild(valueChildren)
  159. }
  160. value.Children[0].Description = "Real Search Control Value"
  161. value.Children[0].Children[0].Description = "Paging Size"
  162. value.Children[0].Children[1].Description = "Cookie"
  163. case ControlTypeBeheraPasswordPolicy:
  164. value.Description += " (Password Policy - Behera Draft)"
  165. if value.Value != nil {
  166. valueChildren := ber.DecodePacket(value.Data.Bytes())
  167. value.Data.Truncate(0)
  168. value.Value = nil
  169. value.AppendChild(valueChildren)
  170. }
  171. sequence := value.Children[0]
  172. for _, child := range sequence.Children {
  173. if child.Tag == 0 {
  174. //Warning
  175. child := child.Children[0]
  176. packet := ber.DecodePacket(child.Data.Bytes())
  177. val, ok := packet.Value.(int64)
  178. if ok {
  179. if child.Tag == 0 {
  180. //timeBeforeExpiration
  181. value.Description += " (TimeBeforeExpiration)"
  182. child.Value = val
  183. } else if child.Tag == 1 {
  184. //graceAuthNsRemaining
  185. value.Description += " (GraceAuthNsRemaining)"
  186. child.Value = val
  187. }
  188. }
  189. } else if child.Tag == 1 {
  190. // Error
  191. packet := ber.DecodePacket(child.Data.Bytes())
  192. val, ok := packet.Value.(int8)
  193. if !ok {
  194. val = -1
  195. }
  196. child.Description = "Error"
  197. child.Value = val
  198. }
  199. }
  200. }
  201. }
  202. }
  203. func addRequestDescriptions(packet *ber.Packet) {
  204. packet.Description = "LDAP Request"
  205. packet.Children[0].Description = "Message ID"
  206. packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
  207. if len(packet.Children) == 3 {
  208. addControlDescriptions(packet.Children[2])
  209. }
  210. }
  211. func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
  212. resultCode, _ := getLDAPResultCode(packet)
  213. packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
  214. packet.Children[1].Children[1].Description = "Matched DN"
  215. packet.Children[1].Children[2].Description = "Error Message"
  216. if len(packet.Children[1].Children) > 3 {
  217. packet.Children[1].Children[3].Description = "Referral"
  218. }
  219. if len(packet.Children) == 3 {
  220. addControlDescriptions(packet.Children[2])
  221. }
  222. }
  223. func DebugBinaryFile(fileName string) error {
  224. file, err := ioutil.ReadFile(fileName)
  225. if err != nil {
  226. return NewError(ErrorDebugging, err)
  227. }
  228. ber.PrintBytes(os.Stdout, file, "")
  229. packet := ber.DecodePacket(file)
  230. addLDAPDescriptions(packet)
  231. ber.PrintPacket(packet)
  232. return nil
  233. }
  234. var hex = "0123456789abcdef"
  235. func mustEscape(c byte) bool {
  236. return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0
  237. }
  238. // EscapeFilter escapes from the provided LDAP filter string the special
  239. // characters in the set `()*\` and those out of the range 0 < c < 0x80,
  240. // as defined in RFC4515.
  241. func EscapeFilter(filter string) string {
  242. escape := 0
  243. for i := 0; i < len(filter); i++ {
  244. if mustEscape(filter[i]) {
  245. escape++
  246. }
  247. }
  248. if escape == 0 {
  249. return filter
  250. }
  251. buf := make([]byte, len(filter)+escape*2)
  252. for i, j := 0, 0; i < len(filter); i++ {
  253. c := filter[i]
  254. if mustEscape(c) {
  255. buf[j+0] = '\\'
  256. buf[j+1] = hex[c>>4]
  257. buf[j+2] = hex[c&0xf]
  258. j += 3
  259. } else {
  260. buf[j] = c
  261. j++
  262. }
  263. }
  264. return string(buf)
  265. }