s4-dsdb Add ability to force a particular SID in the upgrade case
[amitay/samba.git] / source4 / dsdb / common / util_samr.c
index 3a6be10a883ed55860f96b8008a12ccd84ce471a..3ce8d76018da191bb004596b470cffea6ee78347 100644 (file)
@@ -26,7 +26,9 @@
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "../libds/common/flags.h"
-#include "libcli/security/dom_sid.h"
+#include "libcli/security/security.h"
+
+#include "libds/common/flag_mapping.h"
 
 /* Add a user, SAMR style, including the correct transaction
  * semantics.  Used by the SAMR server and by pdb_samba4 */
@@ -34,6 +36,7 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
                       TALLOC_CTX *mem_ctx,
                       const char *account_name,
                       uint32_t acct_flags,
+                      const struct dom_sid *forced_sid,
                       struct dom_sid **sid,
                       struct ldb_dn **dn)
 {
@@ -115,8 +118,6 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
                cn_name[cn_name_len - 1] = '\0';
                container = "CN=Computers";
                obj_class = "computer";
-               samdb_msg_add_uint(ldb, tmp_ctx, msg,
-                       "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
 
        } else if (acct_flags == ACB_SVRTRUST) {
                if (cn_name[cn_name_len - 1] != '$') {
@@ -126,8 +127,6 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
                cn_name[cn_name_len - 1] = '\0';
                container = "OU=Domain Controllers";
                obj_class = "computer";
-               samdb_msg_add_uint(ldb, tmp_ctx, msg,
-                       "primaryGroupID", DOMAIN_RID_DCS);
        } else {
                ldb_transaction_cancel(ldb);
                talloc_free(tmp_ctx);
@@ -142,10 +141,20 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
                return NT_STATUS_FOOBAR;
        }
 
-       samdb_msg_add_string(ldb, tmp_ctx, msg, "sAMAccountName",
-               account_name);
-       samdb_msg_add_string(ldb, tmp_ctx, msg, "objectClass",
-               obj_class);
+       ldb_msg_add_string(msg, "sAMAccountName", account_name);
+       ldb_msg_add_string(msg, "objectClass", obj_class);
+
+       /* This is only here for migrations using pdb_samba4, the
+        * caller and the samldb are responsible for ensuring it makes
+        * sense */
+       if (forced_sid) {
+               ret = samdb_msg_add_dom_sid(ldb, msg, msg, "objectSID", forced_sid);
+               if (ret != LDB_SUCCESS) {
+                       ldb_transaction_cancel(ldb);
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+       }
 
        /* create the user */
        ret = ldb_add(ldb, msg);
@@ -200,7 +209,7 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
 
        /* Change the account control to be the correct account type.
         * The default is for a workstation account */
-       user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
+       user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
        user_account_control = (user_account_control &
                                ~(UF_NORMAL_ACCOUNT |
                                  UF_INTERDOMAIN_TRUST_ACCOUNT |
@@ -220,7 +229,7 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
 
        if (samdb_msg_add_uint(ldb, tmp_ctx, msg,
                               "userAccountControl",
-                              user_account_control) != 0) {
+                              user_account_control) != LDB_SUCCESS) {
                ldb_transaction_cancel(ldb);
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -248,7 +257,9 @@ NTSTATUS dsdb_add_user(struct ldb_context *ldb,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
        *dn = talloc_steal(mem_ctx, account_dn);
-       *sid = talloc_steal(mem_ctx, account_sid);
+       if (sid) {
+               *sid = talloc_steal(mem_ctx, account_sid);
+       }
        talloc_free(tmp_ctx);
        return NT_STATUS_OK;
 }
@@ -291,8 +302,8 @@ NTSTATUS dsdb_add_domain_group(struct ldb_context *ldb,
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
        }
-       samdb_msg_add_string(ldb, tmp_ctx, msg, "sAMAccountName", groupname);
-       samdb_msg_add_string(ldb, tmp_ctx, msg, "objectClass", "group");
+       ldb_msg_add_string(msg, "sAMAccountName", groupname);
+       ldb_msg_add_string(msg, "objectClass", "group");
 
        /* create the group */
        ret = ldb_add(ldb, msg);
@@ -346,6 +357,11 @@ NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
+       if (ldb_transaction_start(ldb) != LDB_SUCCESS) {
+               DEBUG(0, ("Failed to start transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb)));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
        /* Check if alias already exists */
        name = samdb_search_string(ldb, tmp_ctx, NULL,
                                   "sAMAccountName",
@@ -354,12 +370,14 @@ NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
 
        if (name != NULL) {
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_ALIAS_EXISTS;
        }
 
        msg = ldb_msg_new(tmp_ctx);
        if (msg == NULL) {
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -368,11 +386,12 @@ NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
        ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
        if (!msg->dn) {
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_NO_MEMORY;
        }
 
-       samdb_msg_add_string(ldb, mem_ctx, msg, "sAMAccountName", alias_name);
-       samdb_msg_add_string(ldb, mem_ctx, msg, "objectClass", "group");
+       ldb_msg_add_string(msg, "sAMAccountName", alias_name);
+       ldb_msg_add_string(msg, "objectClass", "group");
        samdb_msg_add_int(ldb, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
 
        /* create the alias */
@@ -382,15 +401,18 @@ NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
                break;
        case LDB_ERR_ENTRY_ALREADY_EXISTS:
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_ALIAS_EXISTS;
        case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_ACCESS_DENIED;
        default:
                DEBUG(0,("Failed to create alias record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn),
                         ldb_errstring(ldb)));
                talloc_free(tmp_ctx);
+               ldb_transaction_cancel(ldb);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -398,10 +420,17 @@ NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
        alias_sid = samdb_search_dom_sid(ldb, tmp_ctx,
                                         msg->dn, "objectSid", NULL);
 
+       if (ldb_transaction_commit(ldb) != LDB_SUCCESS) {
+               DEBUG(0, ("Failed to commit transaction in dsdb_add_domain_alias(): %s\n",
+                         ldb_errstring(ldb)));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
        *dn = talloc_steal(mem_ctx, msg->dn);
        *sid = talloc_steal(mem_ctx, alias_sid);
        talloc_free(tmp_ctx);
 
+
        return NT_STATUS_OK;
 }
 
@@ -413,7 +442,7 @@ NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
                             unsigned int *pnum_members)
 {
        struct ldb_message *msg;
-       unsigned int i;
+       unsigned int i, j;
        int ret;
        struct dom_sid *members;
        struct ldb_message_element *member_el;
@@ -447,6 +476,7 @@ NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
                return NT_STATUS_NO_MEMORY;
        }
 
+       j = 0;
        for (i=0; i <member_el->num_values; i++) {
                struct ldb_dn *member_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb,
                                                               &member_el->values[i]);
@@ -459,17 +489,25 @@ NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
-               status = dsdb_get_extended_dn_sid(member_dn, &members[i], "SID");
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(1, ("Could find SID attribute on extended DN %s\n",
-                                 ldb_dn_get_extended_linearized(tmp_ctx, dn, 1)));
+               status = dsdb_get_extended_dn_sid(member_dn, &members[j],
+                                                 "SID");
+               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                       /* If we fail finding a SID then this is no error since
+                        * it could be a non SAM object - e.g. a contact */
+                       continue;
+               } else if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(1, ("When parsing DN '%s' we failed to parse it's SID component, so we cannot fetch the membership: %s\n",
+                                 ldb_dn_get_extended_linearized(tmp_ctx, member_dn, 1),
+                                 nt_errstr(status)));
                        talloc_free(tmp_ctx);
-                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       return status;
                }
+
+               ++j;
        }
 
        *members_out = talloc_steal(mem_ctx, members);
-       *pnum_members = member_el->num_values;
+       *pnum_members = j;
        talloc_free(tmp_ctx);
        return NT_STATUS_OK;
 }
@@ -502,7 +540,7 @@ NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb,
                                    dom_sid_string(tmp_ctx,
                                                   dom_sid_add_rid(tmp_ctx, domain_sid,
                                                                   rids[i])));
-               if (!dn || !ldb_dn_validate(dn)) {
+               if (dn == NULL) {
                        talloc_free(tmp_ctx);
                        return NT_STATUS_NO_MEMORY;
                }