mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-28 16:48:30 -05:00
108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
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
|
|
}
|