Files
2023-04-19 20:24:34 +02:00

128 lines
3.8 KiB
Go

package ldapserver
import (
"errors"
"fmt"
"net"
ber "github.com/go-asn1-ber/asn1-ber"
"github.com/go-ldap/ldap/v3"
)
func HandleAddRequest(req *ber.Packet, boundDN string, server *Server, conn net.Conn) error {
if boundDN == "" {
return ldap.NewError(ldap.LDAPResultInsufficientAccessRights, errors.New("anonymous Write denied"))
}
addReq, err := parseAddRequest(req)
if err != nil {
return err
}
fnNames := []string{}
for k := range server.AddFns {
fnNames = append(fnNames, k)
}
fn := routeFunc(addReq.DN, fnNames)
var adder Adder
if adder = server.AddFns[fn]; adder == nil {
if fn == "" {
err = fmt.Errorf("no suitable handler found for dn: '%s'", addReq.DN)
} else {
err = fmt.Errorf("handler '%s' does not support add", fn)
}
return ldap.NewError(ldap.LDAPResultUnwillingToPerform, err)
}
code, err := adder.Add(boundDN, addReq, conn)
return ldap.NewError(uint16(code), err)
}
func parseAddRequest(req *ber.Packet) (*ldap.AddRequest, error) {
addReq := ldap.AddRequest{}
// LDAP Add request have 2 Elements (DN and AttributeList)
if len(req.Children) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("invalid add 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)
}
addReq.DN = dn
al, err := parseAttributeList(req.Children[1])
if err != nil {
return nil, err
}
addReq.Attributes = al
return &addReq, nil
}
func parseAttributeList(req *ber.Packet) ([]ldap.Attribute, error) {
ldapAttrs := []ldap.Attribute{}
if req.ClassType != ber.ClassUniversal || req.TagType != ber.TypeConstructed || req.Tag != ber.TagSequence {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute List"))
}
for _, a := range req.Children {
attr, err := parseAttribute(a, false)
if err != nil {
return nil, err
}
ldapAttrs = append(ldapAttrs, *attr)
}
return ldapAttrs, nil
}
func parseAttribute(attr *ber.Packet, partial bool) (*ldap.Attribute, error) {
var la ldap.Attribute
var ok bool
var err error
// Partial attributes, might just contain a type and allow the Value to be absent
if partial && (len(attr.Children) < 1 || len(attr.Children) > 2) {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding partial Attribute"))
} else if !partial && len(attr.Children) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute"))
}
ad := attr.Children[0]
if ad.ClassType != ber.ClassUniversal || ad.TagType != ber.TypePrimitive || ad.Tag != ber.TagOctetString {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute Description"))
}
la.Type, ok = ad.Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute Description"))
}
// We can return here if this is a Partial Attribute without values
if partial && len(attr.Children) == 1 {
return &la, nil
}
if la.Vals, err = parseAttributeValues(attr.Children[1]); err != nil {
return nil, err
}
return &la, nil
}
func parseAttributeValues(values *ber.Packet) ([]string, error) {
var strVals []string
if values.ClassType != ber.ClassUniversal || values.TagType != ber.TypeConstructed || values.Tag != ber.TagSet {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute Values"))
}
for _, value := range values.Children {
strVal, ok := value.Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("error decoding Attribute Value"))
}
strVals = append(strVals, strVal)
}
return strVals, nil
}