r17472: Remove unused variable.
[samba.git] / source4 / libnet / libnet_samsync_ldb.c
index 2baab5328927b754f8b41b6fcba2f51e2269834d..89123932319aaae2a5c36c4369227dcd9dc2d9d4 100644 (file)
 #include "libcli/ldap/ldap.h"
 #include "dsdb/samdb/samdb.h"
 #include "auth/auth.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "db_wrap.h"
+#include "libcli/security/security.h"
+#include "librpc/rpc/dcerpc.h"
 
 struct samsync_ldb_secret {
        struct samsync_ldb_secret *prev, *next;
@@ -43,8 +47,11 @@ struct samsync_ldb_trusted_domain {
 };
 
 struct samsync_ldb_state {
+       /* Values from the LSA lookup */
+       const struct libnet_SamSync_state *samsync_state;
+
        struct dom_sid *dom_sid[3];
-       struct ldb_context *sam_ldb;
+       struct ldb_context *sam_ldb, *remote_ldb;
        struct ldb_dn *base_dn[3];
        struct samsync_ldb_secret *secrets;
        struct samsync_ldb_trusted_domain *trusted_domains;
@@ -53,7 +60,8 @@ struct samsync_ldb_state {
 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
                                                         struct samsync_ldb_state *state,
                                                         struct dom_sid *sid,
-                                                        struct ldb_dn **fsp_dn)
+                                                        struct ldb_dn **fsp_dn,
+                                                        char **error_string)
 {
        const char *sidstr = dom_sid_string(mem_ctx, sid);
        /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
@@ -68,8 +76,10 @@ static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
        }
 
        if (basedn == NULL) {
-               DEBUG(0, ("Failed to find DN for "
-                         "ForeignSecurityPrincipal container\n"));
+               *error_string = talloc_asprintf(mem_ctx, 
+                                               "Failed to find DN for "
+                                               "ForeignSecurityPrincipal container under %s",
+                                               ldb_dn_linearize(mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN]));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
        
@@ -92,10 +102,10 @@ static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
        /* create the alias */
        ret = samdb_add(state->sam_ldb, mem_ctx, msg);
        if (ret != 0) {
-               DEBUG(0,("Failed to create foreignSecurityPrincipal "
-                        "record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "
+                                               "record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msg->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
        return NT_STATUS_OK;
@@ -103,15 +113,20 @@ static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
                                          struct samsync_ldb_state *state,
-                                         struct creds_CredentialState *creds,
                                          enum netr_SamDatabaseID database,
-                                         struct netr_DELTA_ENUM *delta) 
+                                         struct netr_DELTA_ENUM *delta,
+                                         char **error_string) 
 {
        struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
        const char *domain_name = domain->domain_name.string;
        struct ldb_message *msg;
        int ret;
        
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        if (database == SAM_DATABASE_DOMAIN) {
                const char *domain_attrs[] =  {"nETBIOSName", "nCName", NULL};
                struct ldb_message **msgs_domain;
@@ -121,35 +136,54 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
                                          "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
                                          domain_name);
                if (ret_domain == -1) {
+                       *error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
                
                if (ret_domain != 1) {
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,
+                                                       ret_domain);
                        return NT_STATUS_NO_SUCH_DOMAIN;                
                }
 
                state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
 
-               state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
-                                                               state->base_dn[database], 
-                                                               "objectSid", NULL);
+               if (state->dom_sid[database]) {
+                       /* Update the domain sid with the incoming
+                        * domain (found on LSA pipe, database sid may
+                        * be random) */
+                       samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, 
+                                             msg, "objectSid", state->dom_sid[database]);
+               } else {
+                       /* Well, we will have to use the one from the database */
+                       state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
+                                                                       state->base_dn[database], 
+                                                                       "objectSid", NULL);
+               }
+
+               if (state->samsync_state->domain_guid) {
+                       NTSTATUS nt_status;
+                       struct ldb_val v;
+                       nt_status = ndr_push_struct_blob(&v, msg, state->samsync_state->domain_guid,
+                                                        (ndr_push_flags_fn_t)ndr_push_GUID);
+                       if (!NT_STATUS_IS_OK(nt_status)) {
+                               *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
+                               return nt_status;
+                       }
+                       
+                       ldb_msg_add_value(msg, "objectGUID", &v);
+               }
        } else if (database == SAM_DATABASE_BUILTIN) {
                /* work out the builtin_dn - useful for so many calls its worth
                   fetching here */
                const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
                                                           "distinguishedName", "objectClass=builtinDomain");
                state->base_dn[database] = ldb_dn_explode(state, dnstring);
-               state->dom_sid[database] = dom_sid_parse_talloc(state, SID_BUILTIN);
        } else {
                /* PRIVs DB */
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       msg = ldb_msg_new(mem_ctx);
-       if (msg == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
        if (!msg->dn) {
                return NT_STATUS_NO_MEMORY;
@@ -159,19 +193,19 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
                             msg, "oEMInformation", domain->comment.string);
 
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
-                            msg, "forceLogoff", domain->force_logoff_time);
+                           msg, "forceLogoff", domain->force_logoff_time);
 
        samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
-                         msg, "minPwdLen", domain->min_password_length);
+                          msg, "minPwdLen", domain->min_password_length);
 
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
-                         msg, "maxPwdAge", domain->max_password_age);
+                           msg, "maxPwdAge", domain->max_password_age);
 
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
-                         msg, "minPwdAge", domain->min_password_age);
+                           msg, "minPwdAge", domain->min_password_age);
 
        samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
-                         msg, "pwdHistoryLength", domain->password_history_length);
+                          msg, "pwdHistoryLength", domain->password_history_length);
 
        samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
                             msg, "modifiedCount", 
@@ -192,61 +226,99 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
                                        struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
                                        enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta) 
+                                       struct netr_DELTA_ENUM *delta,
+                                       char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct netr_DELTA_USER *user = delta->delta_union.user;
        const char *container, *obj_class;
        char *cn_name;
        int cn_name_len;
-
+       const struct dom_sid *user_sid;
        struct ldb_message *msg;
        struct ldb_message **msgs;
-       int ret;
+       struct ldb_message **remote_msgs = NULL;
+       int ret, i;
        uint32_t acb;
        BOOL add = False;
        const char *attrs[] = { NULL };
+       /* we may change this to a global search, then fill in only the things not in ldap later */
+       const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName", 
+                                      "msDS-KeyVersionNumber", "objectGUID", NULL};
+
+       user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
+       if (!user_sid) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        msg = ldb_msg_new(mem_ctx);
        if (msg == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
+       msg->dn = NULL;
        /* search for the user, by rid */
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
                           &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 
-                          ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
+                          ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
 
        if (ret == -1) {
+               *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s", 
+                                               dom_sid_string(mem_ctx, user_sid),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                add = True;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one user with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB", 
+                                               dom_sid_string(mem_ctx, user_sid));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
-               msg->dn = talloc_steal(msg, msgs[0]->dn);
+               msg->dn = msgs[0]->dn;
+               talloc_steal(msg, msgs[0]->dn);
        }
 
+       /* and do the same on the remote database */
+       if (state->remote_ldb) {
+               ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
+                                  &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))", 
+                                  ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
+               
+               if (ret == -1) {
+                       *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s", 
+                                                       dom_sid_string(mem_ctx, user_sid),
+                                                       ldb_errstring(state->remote_ldb));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               } else if (ret == 0) {
+                       *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)", 
+                                                       ldb_dn_linearize(mem_ctx, state->base_dn[database]),
+                                                       dom_sid_string(mem_ctx, user_sid));
+                       return NT_STATUS_NO_SUCH_USER;
+               } else if (ret > 1) {
+                       *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s", 
+                                                       dom_sid_string(mem_ctx, user_sid));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       
+                       /* Try to put things in the same location as the remote server */
+               } else if (add) {
+                       msg->dn = remote_msgs[0]->dn;
+                       talloc_steal(msg, remote_msgs[0]->dn);
+               }
+       }
 
        cn_name   = talloc_strdup(mem_ctx, user->account_name.string);
        NT_STATUS_HAVE_NO_MEMORY(cn_name);
        cn_name_len = strlen(cn_name);
 
-#define ADD_OR_DEL(type, attrib, field) do {\
-       if (user->field) { \
-               samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
-                                    attrib, user->field); \
-       } else if (!add) { \
-               samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
-                                    attrib); \
-       } \
+#define ADD_OR_DEL(type, attrib, field) do {                           \
+               if (user->field) {                                      \
+                       samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
+                                              attrib, user->field);    \
+               } else if (!add) {                                      \
+                       samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
+                                            attrib);                   \
+               }                                                       \
         } while (0);
 
         ADD_OR_DEL(string, "samAccountName", account_name.string);
@@ -285,7 +357,7 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
        /* Passwords.  Ensure there is no plaintext stored against
         * this entry, as we only have hashes */
        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
-                               "sambaPassword"); 
+                            "sambaPassword"); 
        if (user->lm_password_present) {
                samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
                                   "lmPwdHash", &user->lmpassword);
@@ -310,6 +382,16 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
 
 #undef ADD_OR_DEL
 
+       for (i=0; remote_attrs[i]; i++) {
+               struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
+               if (!el) {
+                       samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
+                                            remote_attrs[i]); 
+               } else {
+                       ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
+               }
+       }
+
        acb = user->acct_flags;
        if (acb & (ACB_WSTRUST)) {
                cn_name[cn_name_len - 1] = '\0';
@@ -330,23 +412,34 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
        if (add) {
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
                                     "objectClass", obj_class);
-               msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
-                                               "CN=%s, CN=%s", cn_name, container);
                if (!msg->dn) {
-                       return NT_STATUS_NO_MEMORY;             
+                       msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
+                                                       "CN=%s, CN=%s", cn_name, container);
+                       if (!msg->dn) {
+                               return NT_STATUS_NO_MEMORY;             
+                       }
                }
 
                ret = samdb_add(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to create user record %s\n",
-                                ldb_dn_linearize(mem_ctx, msg->dn)));
-                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       struct ldb_dn *first_try_dn = msg->dn;
+                       /* Try again with the default DN */
+                       msg->dn = talloc_steal(msg, msgs[0]->dn);
+                       ret = samdb_add(state->sam_ldb, mem_ctx, msg);
+                       if (ret != 0) {
+                               *error_string = talloc_asprintf(mem_ctx, "Failed to create user record.  Tried both %s and %s: %s",
+                                                               ldb_dn_linearize(mem_ctx, first_try_dn),
+                                                               ldb_dn_linearize(mem_ctx, msg->dn),
+                                                               ldb_errstring(state->sam_ldb));
+                               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       }
                }
        } else {
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to modify user record %s\n",
-                                ldb_dn_linearize(mem_ctx, msg->dn)));
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
+                                                       ldb_dn_linearize(mem_ctx, msg->dn),
+                                                       ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        }
@@ -356,9 +449,9 @@ static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
                                        struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
                                        enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta) 
+                                       struct netr_DELTA_ENUM *delta,
+                                       char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct ldb_message **msgs;
@@ -371,24 +464,24 @@ static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_USER;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one user with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
        ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
        if (ret != 0) {
-               DEBUG(0,("Failed to delete user record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msgs[0]->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msgs[0]->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -397,9 +490,9 @@ static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
                                         struct samsync_ldb_state *state,
-                                        struct creds_CredentialState *creds,
                                         enum netr_SamDatabaseID database,
-                                        struct netr_DELTA_ENUM *delta) 
+                                        struct netr_DELTA_ENUM *delta,
+                                        char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct netr_DELTA_GROUP *group = delta->delta_union.group;
@@ -423,16 +516,16 @@ static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                add = True;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one group/alias with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                msg->dn = talloc_steal(msg, msgs[0]->dn);
@@ -440,14 +533,14 @@ static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
 
        cn_name   = group->group_name.string;
 
-#define ADD_OR_DEL(type, attrib, field) do {\
-       if (group->field) { \
-               samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
-                                    attrib, group->field); \
-       } else if (!add) { \
-               samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
-                                    attrib); \
-       } \
+#define ADD_OR_DEL(type, attrib, field) do {                           \
+               if (group->field) {                                     \
+                       samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
+                                              attrib, group->field);   \
+               } else if (!add) {                                      \
+                       samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
+                                            attrib);                   \
+               }                                                       \
         } while (0);
 
         ADD_OR_DEL(string, "samAccountName", group_name.string);
@@ -475,17 +568,17 @@ static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
 
                ret = samdb_add(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to create group record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn),
-                        ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
+                                                       ldb_dn_linearize(mem_ctx, msg->dn),
+                                                       ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        } else {
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to modify group record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn),
-                        ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
+                                                       ldb_dn_linearize(mem_ctx, msg->dn),
+                                                       ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        }
@@ -494,10 +587,10 @@ static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
-                                       struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
-                                       enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta
+                                        struct samsync_ldb_state *state,
+                                        enum netr_SamDatabaseID database,
+                                        struct netr_DELTA_ENUM *delta,
+                                        char **error_string
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct ldb_message **msgs;
@@ -510,24 +603,24 @@ static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_GROUP;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one group/alias with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
        
        ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
        if (ret != 0) {
-               DEBUG(0,("Failed to delete group record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msgs[0]->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msgs[0]->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -536,9 +629,9 @@ static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
                                                struct samsync_ldb_state *state,
-                                               struct creds_CredentialState *creds,
                                                enum netr_SamDatabaseID database,
-                                               struct netr_DELTA_ENUM *delta) 
+                                               struct netr_DELTA_ENUM *delta,
+                                               char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
@@ -559,16 +652,16 @@ static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_GROUP;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one group/alias with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                msg->dn = talloc_steal(msg, msgs[0]->dn);
@@ -581,9 +674,9 @@ static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
                ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
                                   "(&(objectClass=user)(objectSid=%s))", 
                                   ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i]))); 
-
+               
                if (ret == -1) {
-                       DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                } else if (ret == 0) {
                        return NT_STATUS_NO_SUCH_USER;
@@ -592,15 +685,15 @@ static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
                } else {
                        samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
                }
-       
+               
                talloc_free(msgs);
        }
-
+       
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
        if (ret != 0) {
-               DEBUG(0,("Failed to modify group record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msg->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -609,9 +702,9 @@ static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
                                         struct samsync_ldb_state *state,
-                                        struct creds_CredentialState *creds,
                                         enum netr_SamDatabaseID database,
-                                        struct netr_DELTA_ENUM *delta) 
+                                        struct netr_DELTA_ENUM *delta,
+                                        char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
@@ -635,16 +728,16 @@ static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                add = True;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one group/alias with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
@@ -652,17 +745,17 @@ static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
 
        cn_name   = alias->alias_name.string;
 
-#define ADD_OR_DEL(type, attrib, field) do {\
-       if (alias->field) { \
-               samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
-                                    attrib, alias->field); \
-       } else if (!add) { \
-               samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
-                                    attrib); \
-       } \
-        } while (0);
+#define ADD_OR_DEL(type, attrib, field) do {                           \
+               if (alias->field) {                                     \
+                       samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
+                                              attrib, alias->field);   \
+               } else if (!add) {                                      \
+                       samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
+                                            attrib);                   \
+               }                                                       \
+       } while (0);
 
-        ADD_OR_DEL(string, "samAccountName", alias_name.string);
+       ADD_OR_DEL(string, "samAccountName", alias_name.string);
 
        if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
                                  "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
@@ -689,17 +782,17 @@ static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
 
                ret = samdb_add(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to create alias record %s: %s\n",
-                                ldb_dn_linearize(mem_ctx, msg->dn),
-                                ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
+                                                       ldb_dn_linearize(mem_ctx, msg->dn),
+                                                       ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        } else {
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
                if (ret != 0) {
-                       DEBUG(0,("Failed to modify alias record %s: %s\n",
-                                ldb_dn_linearize(mem_ctx, msg->dn),
-                                ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
+                                                       ldb_dn_linearize(mem_ctx, msg->dn),
+                                                       ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        }
@@ -708,10 +801,10 @@ static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
-                                       struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
-                                       enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta
+                                        struct samsync_ldb_state *state,
+                                        enum netr_SamDatabaseID database,
+                                        struct netr_DELTA_ENUM *delta,
+                                        char **error_string
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct ldb_message **msgs;
@@ -724,7 +817,7 @@ static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_ALIAS;
@@ -734,9 +827,9 @@ static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
 
        ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
        if (ret != 0) {
-               DEBUG(0,("Failed to delete alias record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msgs[0]->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msgs[0]->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -745,9 +838,9 @@ static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
                                                struct samsync_ldb_state *state,
-                                               struct creds_CredentialState *creds,
                                                enum netr_SamDatabaseID database,
-                                               struct netr_DELTA_ENUM *delta) 
+                                               struct netr_DELTA_ENUM *delta,
+                                               char **error_string) 
 {
        uint32_t rid = delta->delta_id_union.rid;
        struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
@@ -766,18 +859,18 @@ static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
                           "(&(objectClass=group)(objectSid=%s))", 
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
-
+               
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_GROUP;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one group/alias with SID: %s\n", 
-                         dom_sid_string(mem_ctx, 
-                                        dom_sid_add_rid(mem_ctx, 
-                                                        state->dom_sid[database], 
-                                                        rid))));
+               *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
+                                               dom_sid_string(mem_ctx, 
+                                                              dom_sid_add_rid(mem_ctx, 
+                                                                              state->dom_sid[database], 
+                                                                              rid)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                msg->dn = talloc_steal(msg, msgs[0]->dn);
@@ -793,17 +886,18 @@ static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
                                   ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid)); 
 
                if (ret == -1) {
-                       DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+                       *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                } else if (ret == 0) {
                        NTSTATUS nt_status;
                        nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
                                                                             alias_member->sids.sids[i].sid, 
-                                                                            &alias_member_dn);
+                                                                            &alias_member_dn, 
+                                                                            error_string);
                        if (!NT_STATUS_IS_OK(nt_status)) {
                                return nt_status;
                        }
-               } else if (ret > 1) {
+               } else if (ret > 1) {
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                } else {
                        alias_member_dn = msgs[0]->dn;
@@ -815,9 +909,9 @@ static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
 
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
        if (ret != 0) {
-               DEBUG(0,("Failed to modify group record %s: %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn),
-                        ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
+                                               ldb_dn_linearize(mem_ctx, msg->dn),
+                                               ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -825,10 +919,10 @@ static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
-                                       struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
-                                       enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta
+                                          struct samsync_ldb_state *state,
+                                          enum netr_SamDatabaseID database,
+                                          struct netr_DELTA_ENUM *delta,
+                                          char **error_string
 {
        struct dom_sid *sid = delta->delta_id_union.sid;
        struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
@@ -850,20 +944,21 @@ static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
                           "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                NTSTATUS nt_status;
                nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
                                                                     sid,
-                                                                    &privilege_dn);
+                                                                    &privilege_dn,
+                                                                    error_string);
                privilege_dn = talloc_steal(msg, privilege_dn);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        return nt_status;
                }
        } else if (ret > 1) {
-               DEBUG(0, ("More than one account with SID: %s\n", 
-                         dom_sid_string(mem_ctx, sid)));
+               *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
+                                               dom_sid_string(mem_ctx, sid));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                privilege_dn = talloc_steal(msg, msgs[0]->dn);
@@ -878,8 +973,8 @@ static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
 
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
        if (ret != 0) {
-               DEBUG(0,("Failed to modify privilege record %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
+                                               ldb_dn_linearize(mem_ctx, msg->dn));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -887,10 +982,10 @@ static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
-                                       struct samsync_ldb_state *state,
-                                       struct creds_CredentialState *creds,
-                                       enum netr_SamDatabaseID database,
-                                       struct netr_DELTA_ENUM *delta
+                                          struct samsync_ldb_state *state,
+                                          enum netr_SamDatabaseID database,
+                                          struct netr_DELTA_ENUM *delta,
+                                          char **error_string
 {
        struct dom_sid *sid = delta->delta_id_union.sid;
 
@@ -910,13 +1005,13 @@ static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
                           ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
 
        if (ret == -1) {
-               DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
+               *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else if (ret == 0) {
                return NT_STATUS_NO_SUCH_USER;
        } else if (ret > 1) {
-               DEBUG(0, ("More than one account with SID: %s\n", 
-                         dom_sid_string(mem_ctx, sid)));
+               *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
+                                               dom_sid_string(mem_ctx, sid));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
                msg->dn = talloc_steal(msg, msgs[0]->dn);
@@ -927,8 +1022,8 @@ static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
 
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
        if (ret != 0) {
-               DEBUG(0,("Failed to modify privilege record %s\n",
-                        ldb_dn_linearize(mem_ctx, msg->dn)));
+               *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
+                                               ldb_dn_linearize(mem_ctx, msg->dn));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -936,14 +1031,13 @@ static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,             
-                                 void *private,                        
-                                 struct creds_CredentialState *creds,
-                                 enum netr_SamDatabaseID database,
-                                 struct netr_DELTA_ENUM *delta,
-                                 char **error_string)
+                                     void *private,                    
+                                     enum netr_SamDatabaseID database,
+                                     struct netr_DELTA_ENUM *delta,
+                                     char **error_string)
 {
        NTSTATUS nt_status = NT_STATUS_OK;
-       struct samsync_ldb_state *state = private;
+       struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state);
 
        *error_string = NULL;
        switch (delta->delta_type) {
@@ -951,108 +1045,150 @@ static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
        {
                nt_status = samsync_ldb_handle_domain(mem_ctx, 
                                                      state,
-                                                     creds,
                                                      database,
-                                                     delta);
+                                                     delta,
+                                                     error_string);
                break;
        }
        case NETR_DELTA_USER:
        {
                nt_status = samsync_ldb_handle_user(mem_ctx, 
                                                    state,
-                                                   creds,
                                                    database,
-                                                   delta);
+                                                   delta,
+                                                   error_string);
                break;
        }
        case NETR_DELTA_DELETE_USER:
        {
                nt_status = samsync_ldb_delete_user(mem_ctx, 
                                                    state,
-                                                   creds,
                                                    database,
-                                                   delta);
+                                                   delta,
+                                                   error_string);
                break;
        }
        case NETR_DELTA_GROUP:
        {
                nt_status = samsync_ldb_handle_group(mem_ctx, 
                                                     state,
-                                                    creds,
                                                     database,
-                                                    delta);
+                                                    delta,
+                                                    error_string);
                break;
        }
        case NETR_DELTA_DELETE_GROUP:
        {
                nt_status = samsync_ldb_delete_group(mem_ctx, 
-                                                   state,
-                                                   creds,
-                                                   database,
-                                                   delta);
+                                                    state,
+                                                    database,
+                                                    delta,
+                                                    error_string);
                break;
        }
        case NETR_DELTA_GROUP_MEMBER:
        {
                nt_status = samsync_ldb_handle_group_member(mem_ctx, 
                                                            state,
-                                                           creds,
                                                            database,
-                                                           delta);
+                                                           delta,
+                                                           error_string);
                break;
        }
        case NETR_DELTA_ALIAS:
        {
                nt_status = samsync_ldb_handle_alias(mem_ctx, 
                                                     state,
-                                                    creds,
                                                     database,
-                                                    delta);
+                                                    delta,
+                                                    error_string);
                break;
        }
        case NETR_DELTA_DELETE_ALIAS:
        {
                nt_status = samsync_ldb_delete_alias(mem_ctx, 
-                                                   state,
-                                                   creds,
-                                                   database,
-                                                   delta);
+                                                    state,
+                                                    database,
+                                                    delta,
+                                                    error_string);
                break;
        }
        case NETR_DELTA_ALIAS_MEMBER:
        {
                nt_status = samsync_ldb_handle_alias_member(mem_ctx, 
                                                            state,
-                                                           creds,
                                                            database,
-                                                           delta);
+                                                           delta,
+                                                           error_string);
                break;
        }
        case NETR_DELTA_ACCOUNT:
        {
                nt_status = samsync_ldb_handle_account(mem_ctx, 
-                                                    state,
-                                                    creds,
-                                                    database,
-                                                    delta);
+                                                      state,
+                                                      database,
+                                                      delta,
+                                                      error_string);
                break;
        }
        case NETR_DELTA_DELETE_ACCOUNT:
        {
                nt_status = samsync_ldb_delete_account(mem_ctx, 
-                                                   state,
-                                                   creds,
-                                                   database,
-                                                   delta);
+                                                      state,
+                                                      database,
+                                                      delta,
+                                                      error_string);
                break;
        }
        default:
                /* Can't dump them all right now */
                break;
        }
+       if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
+               *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
+       }
        return nt_status;
 }
 
+static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,           
+                                       void *private,
+                                       struct libnet_SamSync_state *samsync_state,
+                                       char **error_string)
+{
+       struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state);
+       const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
+       char *ldap_url;
+
+       state->samsync_state = samsync_state;
+
+       ZERO_STRUCT(state->dom_sid);
+       if (state->samsync_state->domain_sid) {
+               state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
+       }
+
+       state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
+
+       if (state->samsync_state->realm) {
+               if (!server || !*server) {
+                       /* huh?  how do we not have a server name?  */
+                       *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available.  How did we connect?");
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               ldap_url = talloc_asprintf(state, "ldap://%s", server);
+               
+               state->remote_ldb = ldb_wrap_connect(mem_ctx, ldap_url, 
+                                                    NULL, state->samsync_state->machine_net_ctx->cred,
+                                                    0, NULL);
+               if (!state->remote_ldb) {
+                       *error_string = talloc_asprintf(mem_ctx, "Failed to connect to remote LDAP server at %s (used to extract additional data in SamSync replication)", ldap_url);
+                       return NT_STATUS_NO_LOGON_SERVERS;
+               }
+       } else {
+               state->remote_ldb = NULL;
+       }
+       return NT_STATUS_OK;
+}
+
 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
 {
        NTSTATUS nt_status;
@@ -1066,15 +1202,18 @@ NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, str
        state->secrets         = NULL;
        state->trusted_domains = NULL;
 
-       state->sam_ldb         = samdb_connect(state, system_session(state));
+       state->sam_ldb         = ldb_wrap_connect(mem_ctx, lp_sam_url(), r->in.session_info,
+                                                 ctx->cred, 0, NULL);
 
        r2.out.error_string    = NULL;
        r2.in.binding_string   = r->in.binding_string;
+       r2.in.init_fn          = libnet_samsync_ldb_init;
        r2.in.delta_fn         = libnet_samsync_ldb_fn;
        r2.in.fn_ctx           = state;
        r2.in.machine_account  = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
        nt_status              = libnet_SamSync_netlogon(ctx, state, &r2);
        r->out.error_string    = r2.out.error_string;
+       talloc_steal(mem_ctx, r->out.error_string);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(state);