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} 45 46func (a AddRequest) encode() *ber.Packet { 47 request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") 48 request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN")) 49 attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") 50 for _, attribute := range a.Attributes { 51 attributes.AppendChild(attribute.encode()) 52 } 53 request.AppendChild(attributes) 54 return request 55} 56 57// Attribute adds an attribute with the given type and values 58func (a *AddRequest) Attribute(attrType string, attrVals []string) { 59 a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals}) 60} 61 62// NewAddRequest returns an AddRequest for the given DN, with no attributes 63func NewAddRequest(dn string) *AddRequest { 64 return &AddRequest{ 65 DN: dn, 66 } 67 68} 69 70// Add performs the given AddRequest 71func (l *Conn) Add(addRequest *AddRequest) error { 72 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") 73 packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) 74 packet.AppendChild(addRequest.encode()) 75 76 l.Debug.PrintPacket(packet) 77 78 msgCtx, err := l.sendMessage(packet) 79 if err != nil { 80 return err 81 } 82 defer l.finishMessage(msgCtx) 83 84 l.Debug.Printf("%d: waiting for response", msgCtx.id) 85 packetResponse, ok := <-msgCtx.responses 86 if !ok { 87 return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) 88 } 89 packet, err = packetResponse.ReadPacket() 90 l.Debug.Printf("%d: got response %p", msgCtx.id, packet) 91 if err != nil { 92 return err 93 } 94 95 if l.Debug { 96 if err := addLDAPDescriptions(packet); err != nil { 97 return err 98 } 99 ber.PrintPacket(packet) 100 } 101 102 if packet.Children[1].Tag == ApplicationAddResponse { 103 resultCode, resultDescription := getLDAPResultCode(packet) 104 if resultCode != 0 { 105 return NewError(resultCode, errors.New(resultDescription)) 106 } 107 } else { 108 log.Printf("Unexpected Response: %d", packet.Children[1].Tag) 109 } 110 111 l.Debug.Printf("%d: returning", msgCtx.id) 112 return nil 113} 114