Files
ldaps/server_modify.go
timmy ab779df95a Allow sending an error message with the ldap response
Cleanup interfaces and allow the errorMessage ldap field to be used

Use the correct ldap server-side error code
LDAPResultNotSupported(92) is for a client side error
LDAPResultUnavailable(52) is for when a subsystem is not available
LDAPResultOther(80) is for generic server errors

Provide better errors

Fix binding dn to connection

Fix tests

Make handleSearchRequest conform to rfc4511

Plumb contexts through all connections

Add a server context instead of a public quit channel
2026-08-06 16:02:23 -07:00

224 lines
6.7 KiB
Go

package ldaps
import (
"context"
"errors"
"fmt"
"net"
ber "github.com/go-asn1-ber/asn1-ber"
"github.com/go-ldap/ldap/v3"
)
func HandleAddRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]Adder, conn net.Conn) error {
if len(req.Children) != 2 {
return ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid add request: no attributes sent"))
}
var ok bool
addReq := ldap.AddRequest{}
addReq.DN, ok = req.Children[0].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading DN: %v", req.Children[0].Value))
}
addReq.Attributes = []ldap.Attribute{}
for _, attr := range req.Children[1].Children {
if len(attr.Children) != 2 {
return ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid add request: no attributes sent"))
}
a := ldap.Attribute{}
a.Type, ok = attr.Children[0].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading attribute name: %v", attr.Children[0].Value))
}
a.Vals = []string{}
for _, val := range attr.Children[1].Children {
v, ok := val.Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading attribute value: %v", attr.Children[1].Value))
}
a.Vals = append(a.Vals, v)
}
addReq.Attributes = append(addReq.Attributes, a)
}
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].Add(ctx, boundDN, addReq, conn)
}
func HandleDeleteRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]Deleter, conn net.Conn) error {
deleteDN := ber.DecodeString(req.Data.Bytes())
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].Delete(ctx, boundDN, deleteDN, conn)
}
func HandleModifyRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]Modifier, conn net.Conn) (*ldap.ModifyResult, error) {
if len(req.Children) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid modify request: no attributes sent"))
}
var ok bool
modReq := ldap.ModifyRequest{}
modReq.DN, ok = req.Children[0].Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading DN: %v", req.Children[0].Value))
}
for _, change := range req.Children[1].Children {
if len(change.Children) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid modify request: no attributes sent"))
}
attr := ldap.PartialAttribute{}
attrs := change.Children[1].Children
if len(attrs) != 2 {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid modify request: no attributes sent"))
}
attr.Type, ok = attrs[0].Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading modify attribute name: %v", attrs[0].Value))
}
for _, val := range attrs[1].Children {
v, ok := val.Value.(string)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading modify attribute value: %v", val.Value))
}
attr.Vals = append(attr.Vals, v)
}
op, ok := change.Children[0].Value.(int64)
if !ok {
return nil, ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading modify operation type: %v", change.Children[0].Value))
}
switch op {
default:
return nil, ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Unrecognized modify attribute %d", op))
case ldap.AddAttribute:
modReq.Add(attr.Type, attr.Vals)
case ldap.DeleteAttribute:
modReq.Delete(attr.Type, attr.Vals)
case ldap.ReplaceAttribute:
modReq.Replace(attr.Type, attr.Vals)
}
}
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].Modify(ctx, boundDN, modReq, conn)
}
func HandleCompareRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]Comparer, conn net.Conn) error {
if len(req.Children) != 2 {
return ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid compare request: no attributes sent"))
}
var (
ok bool
compReq ldap.CompareRequest
)
compReq.DN, ok = req.Children[0].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading compare DN: %v", req.Children[0].Value))
}
ava := req.Children[1]
if len(ava.Children) != 2 {
return ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Error invalid compare request: no attributes sent"))
}
attr, ok := ava.Children[0].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading compare attribute name: %v", ava.Children[0].Value))
}
val, ok := ava.Children[1].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading compare attribute value: %v", ava.Children[1].Value))
}
compReq.Attribute = attr
compReq.Value = val
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].Compare(ctx, boundDN, compReq, conn)
}
func HandleAbandonRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]Abandoner, conn net.Conn) error {
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].Abandon(ctx, boundDN, conn)
}
func HandleModifyDNRequest(ctx context.Context, req *ber.Packet, boundDN string, fns map[string]ModifyDNr, conn net.Conn) error {
if len(req.Children) != 3 && len(req.Children) != 4 {
return ldap.NewError(ldap.LDAPResultProtocolError, errors.New("Invalid packet length"))
}
var (
ok bool
mdnReq ldap.ModifyDNRequest
)
mdnReq.DN, ok = req.Children[0].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading DN: %v", req.Children[0].Value))
}
mdnReq.NewRDN, ok = req.Children[1].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading new RDN: %v", req.Children[1].Value))
}
mdnReq.DeleteOldRDN, ok = req.Children[2].Value.(bool)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading DeleteOldRDN: %v", req.Children[2].Value))
}
if len(req.Children) == 4 {
mdnReq.NewSuperior, ok = req.Children[3].Value.(string)
if !ok {
return ldap.NewError(ldap.LDAPResultProtocolError, fmt.Errorf("Error reading NewSuperior: %v", req.Children[3].Value))
}
}
fnNames := []string{}
for k := range fns {
fnNames = append(fnNames, k)
}
fn := routeFunc(boundDN, fnNames)
return fns[fn].ModifyDN(ctx, boundDN, mdnReq, conn)
}