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