1// 2// https://tools.ietf.org/html/rfc4511 3// 4// AddRequest ::= [APPLICATION 8] SEQUENCE { 5// entry LDAPDN, 6// attributes AttributeList } 7// 8// AttributeList ::= SEQUENCE OF attribute Attribute 9 10package ldap 11 12import ( 13 "errors" 14 "log" 15 16 "gopkg.in/asn1-ber.v1" 17) 18 19// Attribute represents an LDAP attribute 20type Attribute struct { 21 // Type is the name of the LDAP attribute 22 Type string 23 // Vals are the LDAP attribute values 24 Vals []string 25} 26 27func (a *Attribute) encode() *ber.Packet { 28 seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute") 29 seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.Type, "Type")) 30 set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") 31 for _, value := range a.Vals { 32 set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) 33 } 34 seq.AppendChild(set) 35 return seq 36} 37 38// AddRequest represents an LDAP AddRequest operation 39type AddRequest struct { 40 // DN identifies the entry being added 41 DN string 42 // Attributes list the attributes of the new entry 43 Attributes []Attribute 44 // Controls hold optional controls to send with the request 45 Controls []Control 46} 47 48func (a AddRequest) encode() *ber.Packet { 49 request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") 50 request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN")) 51 attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") 52 for _, attribute := range a.Attributes { 53 attributes.AppendChild(attribute.encode()) 54 } 55 request.AppendChild(attributes) 56 return request 57} 58 59// Attribute adds an attribute with the given type and values 60func (a *AddRequest) Attribute(attrType string, attrVals []string) { 61 a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals}) 62} 63 64// NewAddRequest returns an AddRequest for the given DN, with no attributes 65func NewAddRequest(dn string, controls []Control) *AddRequest { 66 return &AddRequest{ 67 DN: dn, 68 Controls: controls, 69 } 70 71} 72 73// Add performs the given AddRequest 74func (l *Conn) Add(addRequest *AddRequest) error { 75 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") 76 packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) 77 packet.AppendChild(addRequest.encode()) 78 if len(addRequest.Controls) > 0 { 79 packet.AppendChild(encodeControls(addRequest.Controls)) 80 } 81 82 l.Debug.PrintPacket(packet) 83 84 msgCtx, err := l.sendMessage(packet) 85 if err != nil { 86 return err 87 } 88 defer l.finishMessage(msgCtx) 89 90 l.Debug.Printf("%d: waiting for response", msgCtx.id) 91 packetResponse, ok := <-msgCtx.responses 92 if !ok { 93 return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) 94 } 95 packet, err = packetResponse.ReadPacket() 96 l.Debug.Printf("%d: got response %p", msgCtx.id, packet) 97 if err != nil { 98 return err 99 } 100 101 if l.Debug { 102 if err := addLDAPDescriptions(packet); err != nil { 103 return err 104 } 105 ber.PrintPacket(packet) 106 } 107 108 if packet.Children[1].Tag == ApplicationAddResponse { 109 err := GetLDAPError(packet) 110 if err != nil { 111 return err 112 } 113 } else { 114 log.Printf("Unexpected Response: %d", packet.Children[1].Tag) 115 } 116 117 l.Debug.Printf("%d: returning", msgCtx.id) 118 return nil 119} 120