-
Notifications
You must be signed in to change notification settings - Fork 6
/
modify.go
107 lines (92 loc) · 3 KB
/
modify.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package ldapserver
import (
"errors"
"fmt"
"net"
ber "github.com/go-asn1-ber/asn1-ber"
"github.com/go-ldap/ldap/v3"
)
func HandleModifyRequest(req *ber.Packet, boundDN string, server *Server, conn net.Conn) error {
if boundDN == "" {
return ldap.NewError(ldap.LDAPResultInsufficientAccessRights, errors.New("anonymous Write denied"))
}
modReq, err := parseModifyRequest(req)
if err != nil {
return err
}
logger.V(1).Info("Parsed Modification", "request", dumpModRequest(modReq))
fnNames := []string{}
for k := range server.ModifyFns {
fnNames = append(fnNames, k)
}
fn := routeFunc(modReq.DN, fnNames)
var modifier Modifier
if modifier = server.ModifyFns[fn]; modifier == nil {
if fn == "" {
err = fmt.Errorf("no suitable handler found for dn: '%s'", modReq.DN)
} else {
err = fmt.Errorf("handler '%s' does not support modify", fn)
}
return ldap.NewError(ldap.LDAPResultUnwillingToPerform, err)
}
code, err := modifier.Modify(boundDN, modReq, conn)
return ldap.NewError(uint16(code), err)
}
func dumpModRequest(mr *ldap.ModifyRequest) string {
str := fmt.Sprintf("dn: %s\n", mr.DN)
for _, change := range mr.Changes {
str += fmt.Sprintf("op: %d\n attr: %s values: %v\n", change.Operation, change.Modification.Type, change.Modification.Vals)
}
return str
}
func parseModifyRequest(req *ber.Packet) (*ldap.ModifyRequest, error) {
modReq := ldap.ModifyRequest{}
// LDAP Modify requests have 2 Elements (DN and AttributeList)
if len(req.Children) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("invalid modify request"))
}
dn, ok := req.Children[0].Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding entry DN"))
}
_, err := ldap.ParseDN(dn)
if err != nil {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, err)
}
modReq.DN = dn
ml, err := parseModList(req.Children[1])
if err != nil {
return nil, err
}
modReq.Changes = ml
return &modReq, nil
}
func parseModList(req *ber.Packet) ([]ldap.Change, error) {
var changes []ldap.Change
if req.ClassType != ber.ClassUniversal || req.TagType != ber.TypeConstructed || req.Tag != ber.TagSequence {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Changes List"))
}
for _, c := range req.Children {
var change ldap.Change
switch c.Children[0].Data.Bytes()[0] {
default:
return nil, ldap.NewError(ldap.LDAPResultDecodingError, errors.New("invalid change operation"))
case ldap.AddAttribute:
change.Operation = ldap.AddAttribute
logger.V(1).Info("op=add")
case ldap.ReplaceAttribute:
change.Operation = ldap.ReplaceAttribute
logger.V(1).Info("op=replace")
case ldap.DeleteAttribute:
change.Operation = ldap.DeleteAttribute
logger.V(1).Info("op=delete")
}
attr, err := parseAttribute(c.Children[1], true)
if err != nil {
return nil, err
}
change.Modification = ldap.PartialAttribute{Type: attr.Type, Vals: attr.Vals}
changes = append(changes, change)
}
return changes, nil
}