In LDAP there is two ways to remove an attribute.
One can remove an attribute by just naming the attribute but it is also
possible to remove a specific attribute: value combo.

In ldapd the latter is broken if the last attribute is removed because
the result of ldap_del_values() is an invalid encoding (empty sequence)
and with that the modification fails because validate_entry() fails.
The error is LDAP_INVALID_SYNTAX and I have noticed that in tools like
shelldap multiple times but never really connected the dots until now.

This is the minimal way of solving this. If ldap_del_values()
removes the last element use ldap_del_attribute() to remove the attribute
but to make this work the ober_scanf_elements() format has to be relaxed
since what we remove no longer parses with "{s(". Is this an acceptable
solution?

-- 
:wq Claudio

Index: attributes.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/attributes.c,v
retrieving revision 1.6
diff -u -p -r1.6 attributes.c
--- attributes.c        24 Oct 2019 12:39:26 -0000      1.6
+++ attributes.c        19 Dec 2021 12:12:48 -0000
@@ -181,7 +181,7 @@ ldap_del_attribute(struct ber_element *e
 
        attr = entry->be_sub;
        while (attr) {
-               if (ober_scanf_elements(attr, "{s(", &s) != 0) {
+               if (ober_scanf_elements(attr, "{s", &s) != 0) {
                        log_warnx("failed to parse attribute");
                        return -1;
                }
@@ -240,6 +240,9 @@ ldap_del_values(struct ber_element *elm,
                        prev = v;
                }
        }
+
+       if (old_vals->be_sub == NULL)
+               return 1;
 
        return 0;
 }
Index: modify.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/modify.c,v
retrieving revision 1.23
diff -u -p -r1.23 modify.c
--- modify.c    24 Oct 2019 12:39:26 -0000      1.23
+++ modify.c    19 Dec 2021 12:20:19 -0000
@@ -334,7 +334,8 @@ ldap_modify(struct request *req)
                         */
                        if (vals->be_sub &&
                            vals->be_sub->be_type == BER_TYPE_OCTETSTRING) {
-                               ldap_del_values(a, vals);
+                               if (ldap_del_values(a, vals) == 1)
+                                       ldap_del_attribute(entry, attr);
                        } else {
                                ldap_del_attribute(entry, attr);
                        }
Index: validate.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/validate.c,v
retrieving revision 1.12
diff -u -p -r1.12 validate.c
--- validate.c  24 Oct 2019 12:39:26 -0000      1.12
+++ validate.c  19 Dec 2021 11:42:48 -0000
@@ -313,6 +313,7 @@ validate_entry(const char *dn, struct be
        objclass = objclass->be_next;           /* skip attribute description */
        for (a = objclass->be_sub; a != NULL; a = a->be_next) {
                if (ober_get_string(a, &s) != 0) {
+                       log_debug("bad ObjectClass encoding");
                        rc = LDAP_INVALID_SYNTAX;
                        goto done;
                }
@@ -396,6 +397,7 @@ validate_entry(const char *dn, struct be
         */
        for (a = entry->be_sub; a != NULL; a = a->be_next) {
                if (ober_scanf_elements(a, "{se{", &s, &vals) != 0) {
+                       log_debug("bad attribue encoding");
                        rc = LDAP_INVALID_SYNTAX;
                        goto done;
                }

Reply via email to