ldap.go 10 KB

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