1 package ldap
2
3 import (
4 "errors"
5 "fmt"
6
7 ber "github.com/go-asn1-ber/asn1-ber"
8 )
9
10
11 const (
12 AddAttribute = 0
13 DeleteAttribute = 1
14 ReplaceAttribute = 2
15 IncrementAttribute = 3
16 )
17
18
19 type PartialAttribute struct {
20
21 Type string
22
23 Vals []string
24 }
25
26 func (p *PartialAttribute) encode() *ber.Packet {
27 seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
28 seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.Type, "Type"))
29 set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
30 for _, value := range p.Vals {
31 set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
32 }
33 seq.AppendChild(set)
34 return seq
35 }
36
37
38 type Change struct {
39
40 Operation uint
41
42 Modification PartialAttribute
43 }
44
45 func (c *Change) encode() *ber.Packet {
46 change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
47 change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
48 change.AppendChild(c.Modification.encode())
49 return change
50 }
51
52
53 type ModifyRequest struct {
54
55 DN string
56
57 Changes []Change
58
59 Controls []Control
60 }
61
62
63 func (req *ModifyRequest) Add(attrType string, attrVals []string) {
64 req.appendChange(AddAttribute, attrType, attrVals)
65 }
66
67
68 func (req *ModifyRequest) Delete(attrType string, attrVals []string) {
69 req.appendChange(DeleteAttribute, attrType, attrVals)
70 }
71
72
73 func (req *ModifyRequest) Replace(attrType string, attrVals []string) {
74 req.appendChange(ReplaceAttribute, attrType, attrVals)
75 }
76
77
78 func (req *ModifyRequest) Increment(attrType string, attrVal string) {
79 req.appendChange(IncrementAttribute, attrType, []string{attrVal})
80 }
81
82 func (req *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
83 req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
84 }
85
86 func (req *ModifyRequest) appendTo(envelope *ber.Packet) error {
87 pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
88 pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
89 changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
90 for _, change := range req.Changes {
91 changes.AppendChild(change.encode())
92 }
93 pkt.AppendChild(changes)
94
95 envelope.AppendChild(pkt)
96 if len(req.Controls) > 0 {
97 envelope.AppendChild(encodeControls(req.Controls))
98 }
99
100 return nil
101 }
102
103
104 func NewModifyRequest(dn string, controls []Control) *ModifyRequest {
105 return &ModifyRequest{
106 DN: dn,
107 Controls: controls,
108 }
109 }
110
111
112 func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
113 msgCtx, err := l.doRequest(modifyRequest)
114 if err != nil {
115 return err
116 }
117 defer l.finishMessage(msgCtx)
118
119 packet, err := l.readPacket(msgCtx)
120 if err != nil {
121 return err
122 }
123
124 if packet.Children[1].Tag == ApplicationModifyResponse {
125 err := GetLDAPError(packet)
126 if err != nil {
127 return err
128 }
129 } else {
130 return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
131 }
132
133 return nil
134 }
135
136
137 type ModifyResult struct {
138
139 Controls []Control
140
141 Referral string
142 }
143
144
145 func (l *Conn) ModifyWithResult(modifyRequest *ModifyRequest) (*ModifyResult, error) {
146 msgCtx, err := l.doRequest(modifyRequest)
147 if err != nil {
148 return nil, err
149 }
150 defer l.finishMessage(msgCtx)
151
152 result := &ModifyResult{
153 Controls: make([]Control, 0),
154 }
155
156 l.Debug.Printf("%d: waiting for response", msgCtx.id)
157 packet, err := l.readPacket(msgCtx)
158 if err != nil {
159 return nil, err
160 }
161
162 switch packet.Children[1].Tag {
163 case ApplicationModifyResponse:
164 if err = GetLDAPError(packet); err != nil {
165 result.Referral = getReferral(err, packet)
166
167 return result, err
168 }
169 if len(packet.Children) == 3 {
170 for _, child := range packet.Children[2].Children {
171 decodedChild, err := DecodeControl(child)
172 if err != nil {
173 return nil, errors.New("failed to decode child control: " + err.Error())
174 }
175 result.Controls = append(result.Controls, decodedChild)
176 }
177 }
178 }
179 l.Debug.Printf("%d: returning", msgCtx.id)
180 return result, nil
181 }
182
View as plain text