s4:operational LDB - don't accidentally "ate" search helper attributes if we need...
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / operational.c
index 3b1b13faf51e9912b7722af1234431f40229bed6..1d0269854f45a7303dfd91946dc0645371228cad 100644 (file)
@@ -72,6 +72,9 @@
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/samdb/ldb_modules/util.h"
 
+#include "auth/auth.h"
+#include "libcli/security/dom_sid.h"
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
 #endif
@@ -106,18 +109,109 @@ static int construct_primary_group_token(struct ldb_module *module,
        ldb = ldb_module_get_ctx(module);
        if (ldb_match_msg_objectclass(msg, "group") == 1) {
                primary_group_token
-                       = samdb_result_rid_from_sid(ldb, msg, "objectSid", 0);
+                       = samdb_result_rid_from_sid(msg, msg, "objectSid", 0);
                if (primary_group_token == 0) {
                        return LDB_SUCCESS;
                }
 
-               return samdb_msg_add_int(ldb, ldb, msg, "primaryGroupToken",
+               return samdb_msg_add_int(ldb, msg, msg, "primaryGroupToken",
                        primary_group_token);
        } else {
                return LDB_SUCCESS;
        }
 }
 
+/*
+  construct the token groups for SAM objects from a message
+*/
+static int construct_token_groups(struct ldb_module *module,
+                                 struct ldb_message *msg)
+{
+       struct ldb_context *ldb;
+       const struct dom_sid *sid;
+
+       ldb = ldb_module_get_ctx(module);
+
+       sid = samdb_result_dom_sid(msg, msg, "objectSid");
+       if (sid != NULL) {
+               NTSTATUS status;
+               uint32_t prim_group_rid;
+               struct dom_sid **sids = NULL;
+               unsigned int i, num_sids = 0;
+               int ret;
+
+               prim_group_rid = samdb_result_uint(msg, "primaryGroupID", 0);
+               if (prim_group_rid != 0) {
+                       struct dom_sid *prim_group_sid;
+
+                       prim_group_sid = dom_sid_add_rid(msg,
+                                                        samdb_domain_sid(ldb),
+                                                        prim_group_rid);
+                       if (prim_group_sid == NULL) {
+                               ldb_oom(ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+
+                       /* onlyChilds = false, we want to consider also the
+                        * "primaryGroupID" for membership */
+                       status = authsam_expand_nested_groups(ldb,
+                                                             prim_group_sid,
+                                                             false, msg,
+                                                             &sids, &num_sids);
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+                               ldb_oom(ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+
+                       for (i = 0; i < num_sids; i++) {
+                               ret = samdb_msg_add_dom_sid(ldb, msg, msg,
+                                                           "tokenGroups",
+                                                           sids[i]);
+                               if (ret != LDB_SUCCESS) {
+                                       talloc_free(sids);
+                                       return ret;
+                               }
+                       }
+
+                       talloc_free(sids);
+               }
+
+               sids = NULL;
+               num_sids = 0;
+
+               /* onlyChils = true, we don't want to have the SAM object itself
+                * in the result */
+               status = authsam_expand_nested_groups(ldb, sid, true, msg,
+                                                     &sids, &num_sids);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               if (!NT_STATUS_IS_OK(status)) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               for (i = 0; i < num_sids; i++) {
+                       ret = samdb_msg_add_dom_sid(ldb, msg, msg,
+                                                   "tokenGroups", sids[i]);
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(sids);
+                               return ret;
+                       }
+               }
+
+               talloc_free(sids);
+       }
+
+       return LDB_SUCCESS;
+}
+
+/*
+  construct the parent GUID for an entry from a message
+*/
 static int construct_parent_guid(struct ldb_module *module,
                                 struct ldb_message *msg)
 {
@@ -207,6 +301,7 @@ static const struct {
        { "structuralObjectClass", "objectClass", NULL , NULL },
        { "canonicalName", "distinguishedName", NULL , construct_canonical_name },
        { "primaryGroupToken", "objectClass", "objectSid", construct_primary_group_token },
+       { "tokenGroups", "objectSid", "primaryGroupID", construct_token_groups },
        { "parentGUID", NULL, NULL, construct_parent_guid },
        { "subSchemaSubEntry", NULL, NULL, construct_subschema_subentry }
 };
@@ -249,7 +344,8 @@ static int operational_search_post_process(struct ldb_module *module,
                                           bool sd_flags_set)
 {
        struct ldb_context *ldb;
-       int i, a=0;
+       unsigned int i, a = 0;
+       bool constructed_attributes = false;
 
        ldb = ldb_module_get_ctx(module);
 
@@ -281,6 +377,7 @@ static int operational_search_post_process(struct ldb_module *module,
 
                        /* construct the new attribute, using either a supplied
                           constructor or a simple copy */
+                       constructed_attributes = true;
                        if (search_sub[i].constructor != NULL) {
                                if (search_sub[i].constructor(module, msg) != LDB_SUCCESS) {
                                        goto failed;
@@ -290,17 +387,23 @@ static int operational_search_post_process(struct ldb_module *module,
                                                     search_sub[i].attr) != LDB_SUCCESS) {
                                goto failed;
                        }
+               }
+       }
 
-                       /* remove the added search attribute, unless it was
-                          asked for by the user */
+       /* Deletion of the search helper attributes are needed if:
+        * - we generated constructed attributes and
+        * - we aren't requesting all attributes
+        */
+       if ((constructed_attributes) && (!ldb_attr_in_list(attrs, "*"))) {
+               for (i=0;i<ARRAY_SIZE(search_sub);i++) {
+                       /* remove the added search helper attributes, unless
+                        * they were asked for by the user */
                        if (search_sub[i].replace != NULL && 
-                           !ldb_attr_in_list(attrs, search_sub[i].replace) &&
-                           !ldb_attr_in_list(attrs, "*")) {
+                           !ldb_attr_in_list(attrs, search_sub[i].replace)) {
                                ldb_msg_remove_attr(msg, search_sub[i].replace);
                        }
                        if (search_sub[i].extra_attr != NULL && 
-                           !ldb_attr_in_list(attrs, search_sub[i].extra_attr) &&
-                           !ldb_attr_in_list(attrs, "*")) {
+                           !ldb_attr_in_list(attrs, search_sub[i].extra_attr)) {
                                ldb_msg_remove_attr(msg, search_sub[i].extra_attr);
                        }
                }
@@ -359,8 +462,7 @@ static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
                return ldb_module_send_entry(ac->req, ares->message, ares->controls);
 
        case LDB_REPLY_REFERRAL:
-               /* ignore referrals */
-               break;
+               return ldb_module_send_referral(ac->req, ares->referral);
 
        case LDB_REPLY_DONE:
 
@@ -378,7 +480,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
        struct operational_context *ac;
        struct ldb_request *down_req;
        const char **search_attrs = NULL;
-       int i, a;
+       unsigned int i, a;
        int ret;
 
        ldb = ldb_module_get_ctx(module);