modify.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright 2014 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. // File contains Modify functionality
  6. //
  7. // https://tools.ietf.org/html/rfc4511
  8. //
  9. // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
  10. // object LDAPDN,
  11. // changes SEQUENCE OF change SEQUENCE {
  12. // operation ENUMERATED {
  13. // add (0),
  14. // delete (1),
  15. // replace (2),
  16. // ... },
  17. // modification PartialAttribute } }
  18. //
  19. // PartialAttribute ::= SEQUENCE {
  20. // type AttributeDescription,
  21. // vals SET OF value AttributeValue }
  22. //
  23. // AttributeDescription ::= LDAPString
  24. // -- Constrained to <attributedescription>
  25. // -- [RFC4512]
  26. //
  27. // AttributeValue ::= OCTET STRING
  28. //
  29. package ldap
  30. import (
  31. "errors"
  32. "log"
  33. "github.com/nmcclain/asn1-ber"
  34. )
  35. const (
  36. AddAttribute = 0
  37. DeleteAttribute = 1
  38. ReplaceAttribute = 2
  39. )
  40. var LDAPModifyAttributeMap = map[uint64]string{
  41. AddAttribute: "Add",
  42. DeleteAttribute: "Delete",
  43. ReplaceAttribute: "Replace",
  44. }
  45. type PartialAttribute struct {
  46. AttrType string
  47. AttrVals []string
  48. }
  49. func (p *PartialAttribute) encode() *ber.Packet {
  50. seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
  51. seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.AttrType, "Type"))
  52. set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
  53. for _, value := range p.AttrVals {
  54. set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
  55. }
  56. seq.AppendChild(set)
  57. return seq
  58. }
  59. type ModifyRequest struct {
  60. Dn string
  61. AddAttributes []PartialAttribute
  62. DeleteAttributes []PartialAttribute
  63. ReplaceAttributes []PartialAttribute
  64. }
  65. func (m *ModifyRequest) Add(attrType string, attrVals []string) {
  66. m.AddAttributes = append(m.AddAttributes, PartialAttribute{AttrType: attrType, AttrVals: attrVals})
  67. }
  68. func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
  69. m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{AttrType: attrType, AttrVals: attrVals})
  70. }
  71. func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
  72. m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{AttrType: attrType, AttrVals: attrVals})
  73. }
  74. func (m ModifyRequest) encode() *ber.Packet {
  75. request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
  76. request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.Dn, "DN"))
  77. changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
  78. for _, attribute := range m.AddAttributes {
  79. change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
  80. change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
  81. change.AppendChild(attribute.encode())
  82. changes.AppendChild(change)
  83. }
  84. for _, attribute := range m.DeleteAttributes {
  85. change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
  86. change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
  87. change.AppendChild(attribute.encode())
  88. changes.AppendChild(change)
  89. }
  90. for _, attribute := range m.ReplaceAttributes {
  91. change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
  92. change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
  93. change.AppendChild(attribute.encode())
  94. changes.AppendChild(change)
  95. }
  96. request.AppendChild(changes)
  97. return request
  98. }
  99. func NewModifyRequest(
  100. dn string,
  101. ) *ModifyRequest {
  102. return &ModifyRequest{
  103. Dn: dn,
  104. }
  105. }
  106. func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
  107. messageID := l.nextMessageID()
  108. packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
  109. packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
  110. packet.AppendChild(modifyRequest.encode())
  111. l.Debug.PrintPacket(packet)
  112. channel, err := l.sendMessage(packet)
  113. if err != nil {
  114. return err
  115. }
  116. if channel == nil {
  117. return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
  118. }
  119. defer l.finishMessage(messageID)
  120. l.Debug.Printf("%d: waiting for response", messageID)
  121. packet = <-channel
  122. l.Debug.Printf("%d: got response %p", messageID, packet)
  123. if packet == nil {
  124. return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
  125. }
  126. if l.Debug {
  127. if err := addLDAPDescriptions(packet); err != nil {
  128. return err
  129. }
  130. ber.PrintPacket(packet)
  131. }
  132. if packet.Children[1].Tag == ApplicationModifyResponse {
  133. resultCode, resultDescription := getLDAPResultCode(packet)
  134. if resultCode != 0 {
  135. return NewError(resultCode, errors.New(resultDescription))
  136. }
  137. } else {
  138. log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
  139. }
  140. l.Debug.Printf("%d: returning", messageID)
  141. return nil
  142. }