ldb-samba: Add new extended match rule DSDB_MATCH_FOR_EXPUNGE
authorAndrew Bartlett <abartlet@samba.org>
Mon, 29 Aug 2016 06:20:18 +0000 (18:20 +1200)
committerGarming Sam <garming@samba.org>
Thu, 1 Sep 2016 03:49:14 +0000 (05:49 +0200)
This allows us to find links that need to be expunged
without passing the whole DB up in the search response.

While each message still needs to be examined, this code
only has to do memory allocation for entries with links

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
lib/ldb-samba/ldb_matching_rules.c
lib/ldb-samba/ldb_matching_rules.h
source4/setup/schema_samba4.ldif

index 637858fb7b3aadbe904e00c5775886c67bbacfc3..aa8697941c6325f3313228fd76f4bca8293c40f4 100644 (file)
@@ -4,6 +4,7 @@
    ldb database library - Extended match rules
 
    Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+   Copyright (C) Andrew Bartlett <abartlet@samba.org>
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -23,6 +24,8 @@
 #include <ldb_module.h>
 #include "dsdb/samdb/samdb.h"
 #include "ldb_matching_rules.h"
+#include "libcli/security/security.h"
+#include "dsdb/common/util.h"
 
 static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
                                             struct ldb_context *ldb,
@@ -324,9 +327,128 @@ static int ldb_comparator_trans(struct ldb_context *ldb,
 }
 
 
+/*
+ * This rule provides match of a link attribute against a 'should be expunged' criteria
+ *
+ * This allows a search filter such as:
+ *
+ * member:1.3.6.1.4.1.7165.4.5.2:=131139216000000000
+ *
+ * This searches the member attribute, but also any member attributes
+ * that are deleted and should be expunged after the specified NTTIME
+ * time.
+ *
+ */
+static int dsdb_match_for_expunge(struct ldb_context *ldb,
+                                 const char *oid,
+                                 const struct ldb_message *msg,
+                                 const char *attribute_to_match,
+                                 const struct ldb_val *value_to_match,
+                                 bool *matched)
+{
+       const struct dsdb_schema *schema;
+       const struct dsdb_attribute *schema_attr;
+       TALLOC_CTX *tmp_ctx;
+       unsigned int i;
+       struct ldb_message_element *el;
+       struct auth_session_info *session_info;
+       uint64_t tombstone_time;
+       *matched = false;
+
+       el = ldb_msg_find_element(msg, attribute_to_match);
+       if (el == NULL) {
+               return LDB_SUCCESS;
+       }
+
+       session_info
+               = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"),
+                                 struct auth_session_info);
+       if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
+               return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+       }
+
+       /*
+        * If the target attribute to match is not a linked attribute, then
+        * the filter evaluates to undefined
+        */
+       schema = dsdb_get_schema(ldb, NULL);
+       if (schema == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* TODO this is O(log n) per attribute */
+       schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
+       if (schema_attr == NULL) {
+               return LDB_ERR_NO_SUCH_ATTRIBUTE;
+       }
+
+       /*
+        * This extended match filter is only valid for forward linked attributes.
+        */
+       if (schema_attr->linkID == 0 || (schema_attr->linkID & 1) == 1) {
+               return LDB_ERR_NO_SUCH_ATTRIBUTE;
+       }
+
+       /* Just check we don't allow the caller to fill our stack */
+       if (value_to_match->length >=64) {
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       } else {
+               char *p = NULL;
+               char s[value_to_match->length+1];
+               memcpy(s, value_to_match->data, value_to_match->length);
+               s[value_to_match->length] = 0;
+               if (s[0] == '\0' || s[0] == '-') {
+                       return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+               }
+               tombstone_time = strtoull(s, &p, 10);
+               if (p == NULL || p == s || *p != '\0' || tombstone_time == ULLONG_MAX) {
+                       return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+               }
+       }
+
+       tmp_ctx = talloc_new(ldb);
+       if (tmp_ctx == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       for (i = 0; i < el->num_values; i++) {
+               NTSTATUS status;
+               struct dsdb_dn *dn;
+               uint64_t rmd_changetime;
+               if (dsdb_dn_is_deleted_val(&el->values[i]) == false) {
+                       continue;
+               }
+
+               dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i],
+                                  schema_attr->syntax->ldap_oid);
+               if (dn == NULL) {
+                       DEBUG(1, ("Error: Failed to parse linked attribute blob of %s.\n", el->name));
+                       continue;
+               }
+
+               status = dsdb_get_extended_dn_uint64(dn->dn, &rmd_changetime,
+                                                    "RMD_CHANGETIME");
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(1, ("Error: RMD_CHANGETIME is missing on a forward link.\n"));
+                       continue;
+               }
+
+               if (rmd_changetime > tombstone_time) {
+                       continue;
+               }
+
+               *matched = true;
+               break;
+       }
+       talloc_free(tmp_ctx);
+       return LDB_SUCCESS;
+}
+
+
 int ldb_register_samba_matching_rules(struct ldb_context *ldb)
 {
-       struct ldb_extended_match_rule *transitive_eval;
+       struct ldb_extended_match_rule *transitive_eval = NULL,
+               *match_for_expunge = NULL;
        int ret;
 
        transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
@@ -338,5 +460,14 @@ int ldb_register_samba_matching_rules(struct ldb_context *ldb)
                return ret;
        }
 
+       match_for_expunge = talloc_zero(ldb, struct ldb_extended_match_rule);
+       match_for_expunge->oid = DSDB_MATCH_FOR_EXPUNGE;
+       match_for_expunge->callback = dsdb_match_for_expunge;
+       ret = ldb_register_extended_match_rule(ldb, match_for_expunge);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(match_for_expunge);
+               return ret;
+       }
+
        return LDB_SUCCESS;
 }
index e969b3d47cf6a4e9d381b7ebee96534aa9c29a45..421e1ceaec88c0c5599ed8431b16faffcf2c99ef 100644 (file)
@@ -24,5 +24,6 @@
 
 /* This rule provides recursive search of a link attribute */
 #define SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL  "1.2.840.113556.1.4.1941"
+#define DSDB_MATCH_FOR_EXPUNGE "1.3.6.1.4.1.7165.4.5.2"
 
 #endif /* _LDB_MATCHING_RULES_H_ */
index 9e3ff9114e499c763ebd1b7c1a9a47d30bd7df32..2e4c16db6907d736982c98de27baca909574323f 100644 (file)
 ############
 # ldap extended matches
 #Allocated: SAMBA_LDAP_MATCH_ALWAYS_FALSE 1.3.6.1.4.1.7165.4.5.1
+#Allocated: DSDB_MATCH_FOR_EXPUNGE 1.3.6.1.4.1.7165.4.5.2
 
 
 #Allocated: (middleName) attributeID: 1.3.6.1.4.1.7165.4.255.1