aboutsummaryrefslogtreecommitdiff
path: root/write.go
diff options
context:
space:
mode:
Diffstat (limited to 'write.go')
-rw-r--r--write.go166
1 files changed, 95 insertions, 71 deletions
diff --git a/write.go b/write.go
index 7a71465..b04cd2c 100644
--- a/write.go
+++ b/write.go
@@ -58,7 +58,16 @@ func (server *Server) handleAddInternal(state *State, r *message.AddRequest) (in
return ldap.LDAPResultEntryAlreadyExists, nil
}
- // TODO: check that parent object exists
+ // Check that parent object exists
+ parentDn := unparseDN(dnSplit[1:])
+ parentExists, err := server.objectExists(parentDn)
+ if err != nil {
+ return ldap.LDAPResultOperationsError, err
+ }
+ if !parentExists {
+ return ldap.LDAPResultNoSuchObject, fmt.Errorf(
+ "Parent object %s does not exist", parentDn)
+ }
// If adding a group, track of who the members will be so that their memberOf field can be updated later
members := []string{}
@@ -77,8 +86,9 @@ func (server *Server) handleAddInternal(state *State, r *message.AddRequest) (in
if err != nil {
return ldap.LDAPResultObjectClassViolation, err
}
- // If they are writing a member key, we have to check they are adding valid members
if strings.EqualFold(key, ATTR_MEMBER) {
+ // If they are writing a member list, we have to check they are adding valid members
+ // Also, rewrite member list to use canonical DN syntax (no spaces, all lowercase)
for _, member := range vals_str {
member_canonical, err := server.checkDN(member, false)
if err != nil {
@@ -93,19 +103,31 @@ func (server *Server) handleAddInternal(state *State, r *message.AddRequest) (in
"Cannot add %s to members, it does not exist!",
member_canonical)
}
+ members = append(members, member_canonical)
}
- members = append(members, vals_str...)
- }
- if prev, ok := entry[key]; ok {
- entry[key] = append(prev, vals_str...)
+ entry[key] = members
} else {
- entry[key] = vals_str
+ if prev, ok := entry[key]; ok {
+ entry[key] = append(prev, vals_str...)
+ } else {
+ entry[key] = vals_str
+ }
}
}
- if _, ok := entry[ATTR_OBJECTCLASS]; !ok {
+ // Ensure object has at least one objectclass value
+ hasObjectClass := false
+ for k := range entry {
+ if strings.EqualFold(k, ATTR_OBJECTCLASS) {
+ hasObjectClass = true
+ break
+ }
+ }
+ if !hasObjectClass {
entry[ATTR_OBJECTCLASS] = []string{"top"}
}
+
+ // Write system attributes
entry[ATTR_CREATORSNAME] = []string{state.login.user}
entry[ATTR_CREATETIMESTAMP] = []string{genTimestamp()}
entry[ATTR_ENTRYUUID] = []string{genUuid()}
@@ -306,11 +328,25 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques
addMembers, delMembers := []string{}, []string{}
// Produce new entry values to be saved
- newEntry := Entry{}
+ entry := Entry{}
+
for _, change := range r.Changes() {
attr := string(change.Modification().Type_())
- values := change.Modification().Vals()
+ changeValues := []string{}
+ for _, v := range change.Modification().Vals() {
+ changeValues = append(changeValues, string(v))
+ }
+ // If we already had an attribute with this name before,
+ // make sure we are using the same lowercase/uppercase
+ for prevAttr := range prevEntry {
+ if strings.EqualFold(attr, prevAttr) {
+ attr = prevAttr
+ break
+ }
+ }
+
+ // Check that this attribute is not system-managed thus restricted
err = checkRestrictedAttr(attr)
if err != nil {
return ldap.LDAPResultObjectClassViolation, err
@@ -326,112 +362,100 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques
return ldap.LDAPResultInsufficientAccessRights, nil
}
- if change.Operation() == ldap.ModifyRequestChangeOperationAdd {
- newEntry[attr] = prevEntry[attr]
- for _, val := range values {
- present := false
- for _, prevVal := range newEntry[attr] {
- if prevVal == string(val) {
- present = true
- break
- }
+ // If we are changing ATTR_MEMBER, rewrite all values to canonical form
+ if strings.EqualFold(attr, ATTR_MEMBER) {
+ for i := range changeValues {
+ canonical_val, err := server.checkDN(changeValues[i], false)
+ if err != nil {
+ return ldap.LDAPResultInvalidDNSyntax, err
}
- if !present {
- newEntry[attr] = append(newEntry[attr], string(val))
+ changeValues[i] = canonical_val
+ }
+ }
+
+ // If we don't yet have a new value for this attr,
+ // but one existed before, initialize entry[attr] to the old value
+ // so that later on what we do is simply modify entry[attr] in place
+ // (this allows to handle sequences of several changes on the same attr)
+ if _, ok := entry[attr]; !ok {
+ if _, ok := prevEntry[attr]; ok {
+ entry[attr] = prevEntry[attr]
+ }
+ }
+
+ // Apply effective modification on entry[attr]
+ if change.Operation() == ldap.ModifyRequestChangeOperationAdd {
+ for _, val := range changeValues {
+ if !listContains(entry[attr], val) {
+ entry[attr] = append(entry[attr], val)
if strings.EqualFold(attr, ATTR_MEMBER) {
- addMembers = append(addMembers, string(val))
+ addMembers = append(addMembers, val)
}
}
}
} else if change.Operation() == ldap.ModifyRequestChangeOperationDelete {
- if len(values) == 0 {
+ if len(changeValues) == 0 {
// Delete everything
- newEntry[attr] = []string{}
if strings.EqualFold(attr, ATTR_MEMBER) {
- delMembers = append(delMembers, prevEntry[attr]...)
+ delMembers = append(delMembers, entry[attr]...)
}
+ entry[attr] = []string{}
} else {
// Delete only those specified
- newEntry[attr] = []string{}
- for _, prevVal := range prevEntry[attr] {
- keep := true
- for _, delVal := range values {
- if string(delVal) == prevVal {
- keep = false
- break
- }
- }
- if keep {
- newEntry[attr] = append(newEntry[attr], prevVal)
+ newList := []string{}
+ for _, prevVal := range entry[attr] {
+ if !listContains(changeValues, prevVal) {
+ newList = append(newList, prevVal)
} else {
if strings.EqualFold(attr, ATTR_MEMBER) {
delMembers = append(delMembers, prevVal)
}
}
}
+ entry[attr] = newList
}
} else if change.Operation() == ldap.ModifyRequestChangeOperationReplace {
- newEntry[attr] = []string{}
- for _, newVal := range values {
- newEntry[attr] = append(newEntry[attr], string(newVal))
- }
if strings.EqualFold(attr, ATTR_MEMBER) {
- for _, newMem := range newEntry[attr] {
- mustAdd := true
- for _, prevMem := range prevEntry[attr] {
- if prevMem == newMem {
- mustAdd = false
- break
- }
- }
- if mustAdd {
+ for _, newMem := range changeValues {
+ if !listContains(entry[attr], newMem) {
addMembers = append(addMembers, newMem)
}
}
- for _, prevMem := range prevEntry[attr] {
- mustDel := true
- for _, newMem := range newEntry[attr] {
- if newMem == prevMem {
- mustDel = false
- break
- }
- }
- if mustDel {
+ for _, prevMem := range entry[attr] {
+ if !listContains(changeValues, prevMem) {
delMembers = append(delMembers, prevMem)
}
}
}
+ entry[attr] = changeValues
}
}
// Check that added members actually exist
for i := range addMembers {
- addMem, err := server.checkDN(addMembers[i], false)
- if err != nil {
- return ldap.LDAPResultInvalidDNSyntax, err
- }
- exists, err := server.objectExists(addMem)
+ exists, err := server.objectExists(addMembers[i])
if err != nil {
return ldap.LDAPResultOperationsError, err
}
if !exists {
return ldap.LDAPResultNoSuchObject, fmt.Errorf(
- "Cannot add member %s, it does not exist", addMem)
+ "Cannot add member %s, it does not exist", addMembers[i])
}
- addMembers[i] = addMem
}
- if v, ok := newEntry[ATTR_OBJECTCLASS]; ok && len(v) == 0 {
- return ldap.LDAPResultInsufficientAccessRights, fmt.Errorf(
- "Cannot remove all objectclass values")
+ for k, v := range entry {
+ if strings.EqualFold(k, ATTR_OBJECTCLASS) && len(v) == 0 {
+ return ldap.LDAPResultInsufficientAccessRights, fmt.Errorf(
+ "Cannot remove all objectclass values")
+ }
}
// Now, the modification has been processed and accepted and we want to commit it
- newEntry[ATTR_MODIFIERSNAME] = []string{state.login.user}
- newEntry[ATTR_MODIFYTIMESTAMP] = []string{genTimestamp()}
+ entry[ATTR_MODIFIERSNAME] = []string{state.login.user}
+ entry[ATTR_MODIFYTIMESTAMP] = []string{genTimestamp()}
// Save the edited values
- err = server.addElements(dn, newEntry)
+ err = server.addElements(dn, entry)
if err != nil {
return ldap.LDAPResultOperationsError, err
}