s3-libnet: Fix Bug #6193: avoid messing with sync_context in libnet_samsync_delta().
[ira/wip.git] / source3 / libnet / libnet_samsync.c
index 64dcf6de51beaca5a6e0664be9ed80d678f5fe17..0c00b8518aef668cb7f89297805c1de4a912e9a6 100644 (file)
@@ -33,7 +33,6 @@
 
 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
                         DATA_BLOB *session_key,
-                        bool rid_crypt,
                         enum netr_SamDatabaseID database_id,
                         struct netr_DELTA_ENUM *delta)
 {
@@ -42,17 +41,29 @@ static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
        struct netr_DELTA_USER *user = delta->delta_union.user;
        struct samr_Password lm_hash;
        struct samr_Password nt_hash;
+       unsigned char zero_buf[16];
 
-       if (rid_crypt) {
-               if (user->lm_password_present) {
+       memset(zero_buf, '\0', sizeof(zero_buf));
+
+       /* Note that win2000 may send us all zeros
+        * for the hashes if it doesn't
+        * think this channel is secure enough. */
+       if (user->lm_password_present) {
+               if (memcmp(user->lmpassword.hash, zero_buf, 16) != 0) {
                        sam_pwd_hash(rid, user->lmpassword.hash, lm_hash.hash, 0);
-                       user->lmpassword = lm_hash;
+               } else {
+                       memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
                }
+               user->lmpassword = lm_hash;
+       }
 
-               if (user->nt_password_present) {
+       if (user->nt_password_present) {
+               if (memcmp(user->ntpassword.hash, zero_buf, 16) != 0) {
                        sam_pwd_hash(rid, user->ntpassword.hash, nt_hash.hash, 0);
-                       user->ntpassword = nt_hash;
+               } else {
+                       memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
                }
+               user->ntpassword = nt_hash;
        }
 
        if (user->user_private_info.SensitiveData) {
@@ -72,26 +83,31 @@ static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
                        return ndr_map_error2ntstatus(ndr_err);
                }
 
+               /* Note that win2000 may send us all zeros
+                * for the hashes if it doesn't
+                * think this channel is secure enough. */
                if (keys.keys.keys2.lmpassword.length == 16) {
-                       if (rid_crypt) {
+                       if (memcmp(keys.keys.keys2.lmpassword.pwd.hash,
+                                       zero_buf, 16) != 0) {
                                sam_pwd_hash(rid,
-                                            keys.keys.keys2.lmpassword.pwd.hash,
-                                            lm_hash.hash, 0);
-                               user->lmpassword = lm_hash;
+                                       keys.keys.keys2.lmpassword.pwd.hash,
+                                       lm_hash.hash, 0);
                        } else {
-                               user->lmpassword = keys.keys.keys2.lmpassword.pwd;
+                               memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
                        }
+                       user->lmpassword = lm_hash;
                        user->lm_password_present = true;
                }
                if (keys.keys.keys2.ntpassword.length == 16) {
-                       if (rid_crypt) {
+                       if (memcmp(keys.keys.keys2.ntpassword.pwd.hash,
+                                               zero_buf, 16) != 0) {
                                sam_pwd_hash(rid,
-                                            keys.keys.keys2.ntpassword.pwd.hash,
-                                            nt_hash.hash, 0);
-                               user->ntpassword = nt_hash;
+                                       keys.keys.keys2.ntpassword.pwd.hash,
+                                       nt_hash.hash, 0);
                        } else {
-                               user->ntpassword = keys.keys.keys2.ntpassword.pwd;
+                               memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
                        }
+                       user->ntpassword = nt_hash;
                        user->nt_password_present = true;
                }
                /* TODO: rid decrypt history fields */
@@ -129,7 +145,6 @@ static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
                                  DATA_BLOB *session_key,
-                                 bool rid_crypt,
                                  enum netr_SamDatabaseID database_id,
                                  struct netr_DELTA_ENUM *delta)
 {
@@ -140,7 +155,6 @@ static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
 
                        status = fix_user(mem_ctx,
                                          session_key,
-                                         rid_crypt,
                                          database_id,
                                          delta);
                        break;
@@ -165,7 +179,6 @@ static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
                                        DATA_BLOB *session_key,
-                                       bool rid_crypt,
                                        enum netr_SamDatabaseID database_id,
                                        struct netr_DELTA_ENUM_ARRAY *r)
 {
@@ -176,7 +189,6 @@ static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
 
                status = samsync_fix_delta(mem_ctx,
                                           session_key,
-                                          rid_crypt,
                                           database_id,
                                           &r->delta_enum[i]);
                if (!NT_STATUS_IS_OK(status)) {
@@ -270,47 +282,112 @@ static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
  * libnet_samsync
  */
 
-NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
-                       struct samsync_context *ctx)
+static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
+                                           struct netr_ChangeLogEntry *e)
+{
+       ZERO_STRUCTP(e);
+
+       e->db_index             = o->database_id;
+       e->delta_type           = o->object_type;
+
+       switch (e->delta_type) {
+               case NETR_DELTA_DOMAIN:
+               case NETR_DELTA_DELETE_GROUP:
+               case NETR_DELTA_RENAME_GROUP:
+               case NETR_DELTA_DELETE_USER:
+               case NETR_DELTA_RENAME_USER:
+               case NETR_DELTA_DELETE_ALIAS:
+               case NETR_DELTA_RENAME_ALIAS:
+               case NETR_DELTA_DELETE_TRUST:
+               case NETR_DELTA_DELETE_ACCOUNT:
+               case NETR_DELTA_DELETE_SECRET:
+               case NETR_DELTA_DELETE_GROUP2:
+               case NETR_DELTA_DELETE_USER2:
+               case NETR_DELTA_MODIFY_COUNT:
+                       break;
+               case NETR_DELTA_USER:
+               case NETR_DELTA_GROUP:
+               case NETR_DELTA_GROUP_MEMBER:
+               case NETR_DELTA_ALIAS:
+               case NETR_DELTA_ALIAS_MEMBER:
+                       e->object_rid = o->object_identifier.rid;
+                       break;
+               case NETR_DELTA_SECRET:
+                       e->object.object_name = o->object_identifier.name;
+                       e->flags = NETR_CHANGELOG_NAME_INCLUDED;
+                       break;
+               case NETR_DELTA_TRUSTED_DOMAIN:
+               case NETR_DELTA_ACCOUNT:
+               case NETR_DELTA_POLICY:
+                       e->object.object_sid = o->object_identifier.sid;
+                       e->flags = NETR_CHANGELOG_SID_INCLUDED;
+                       break;
+               default:
+                       break;
+       }
+}
+
+/**
+ * libnet_samsync_delta
+ */
+
+static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
+                                    enum netr_SamDatabaseID database_id,
+                                    uint64_t *sequence_num,
+                                    struct samsync_context *ctx,
+                                    struct netr_ChangeLogEntry *e)
 {
        NTSTATUS result;
-       TALLOC_CTX *mem_ctx;
+       NTSTATUS callback_status;
        const char *logon_server = ctx->cli->desthost;
        const char *computername = global_myname();
        struct netr_Authenticator credential;
        struct netr_Authenticator return_authenticator;
        uint16_t restart_state = 0;
        uint32_t sync_context = 0;
-       const char *debug_str;
        DATA_BLOB session_key;
 
        ZERO_STRUCT(return_authenticator);
 
-       if (!(mem_ctx = talloc_init("libnet_samsync"))) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
-       if (debug_str) {
-               d_fprintf(stderr, "%s\n", debug_str);
-       }
-
        do {
                struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
-               NTSTATUS callback_status;
 
                netlogon_creds_client_step(ctx->cli->dc, &credential);
 
-               result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
-                                                  logon_server,
-                                                  computername,
-                                                  &credential,
-                                                  &return_authenticator,
-                                                  database_id,
-                                                  restart_state,
-                                                  &sync_context,
-                                                  &delta_enum_array,
-                                                  0xffff);
+               if (ctx->single_object_replication &&
+                   !ctx->force_full_replication) {
+                       result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
+                                                         logon_server,
+                                                         computername,
+                                                         &credential,
+                                                         &return_authenticator,
+                                                         *e,
+                                                         0,
+                                                         &delta_enum_array);
+               } else if (!ctx->force_full_replication &&
+                          sequence_num && (*sequence_num > 0)) {
+                       result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
+                                                           logon_server,
+                                                           computername,
+                                                           &credential,
+                                                           &return_authenticator,
+                                                           database_id,
+                                                           sequence_num,
+                                                           &delta_enum_array,
+                                                           0xffff);
+               } else {
+                       result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
+                                                          logon_server,
+                                                          computername,
+                                                          &credential,
+                                                          &return_authenticator,
+                                                          database_id,
+                                                          restart_state,
+                                                          &sync_context,
+                                                          &delta_enum_array,
+                                                          0xffff);
+               }
+
                if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
                        return result;
                }
@@ -330,14 +407,14 @@ NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
 
                samsync_fix_delta_array(mem_ctx,
                                        &session_key,
-                                       false,
                                        database_id,
                                        delta_enum_array);
 
                /* Process results */
-               callback_status = ctx->delta_fn(mem_ctx, database_id,
-                                               delta_enum_array,
-                                               NT_STATUS_IS_OK(result), ctx);
+               callback_status = ctx->ops->process_objects(mem_ctx, database_id,
+                                                           delta_enum_array,
+                                                           sequence_num,
+                                                           ctx);
                if (!NT_STATUS_IS_OK(callback_status)) {
                        result = callback_status;
                        goto out;
@@ -345,20 +422,89 @@ NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
 
                TALLOC_FREE(delta_enum_array);
 
-               /* Increment sync_context */
-               sync_context += 1;
-
        } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
  out:
-       if (NT_STATUS_IS_ERR(result) && !ctx->error_message) {
+
+       return result;
+}
+
+/**
+ * libnet_samsync
+ */
+
+NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
+                       struct samsync_context *ctx)
+{
+       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS callback_status;
+       TALLOC_CTX *mem_ctx;
+       const char *debug_str;
+       uint64_t sequence_num = 0;
+       int i = 0;
+
+       if (!(mem_ctx = talloc_new(ctx))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!ctx->ops) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (ctx->ops->startup) {
+               status = ctx->ops->startup(mem_ctx, ctx,
+                                          database_id, &sequence_num);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto done;
+               }
+       }
+
+       debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
+       if (debug_str) {
+               d_fprintf(stderr, "%s\n", debug_str);
+       }
+
+       if (!ctx->single_object_replication) {
+               status = libnet_samsync_delta(mem_ctx, database_id,
+                                             &sequence_num, ctx, NULL);
+               goto done;
+       }
+
+       for (i=0; i<ctx->num_objects; i++) {
+
+               struct netr_ChangeLogEntry e;
+
+               if (ctx->objects[i].database_id != database_id) {
+                       continue;
+               }
+
+               libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
+
+               status = libnet_samsync_delta(mem_ctx, database_id,
+                                             &sequence_num, ctx, &e);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto done;
+               }
+       }
+
+ done:
+
+       if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
+               callback_status = ctx->ops->finish(mem_ctx, ctx,
+                                                  database_id, sequence_num);
+               if (!NT_STATUS_IS_OK(callback_status)) {
+                       status = callback_status;
+               }
+       }
+
+       if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
 
                ctx->error_message = talloc_asprintf(ctx,
                        "Failed to fetch %s database: %s",
                        samsync_database_str(database_id),
-                       nt_errstr(result));
+                       nt_errstr(status));
 
-               if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
 
                        ctx->error_message =
                                talloc_asprintf_append(ctx->error_message,
@@ -369,7 +515,7 @@ NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
 
        talloc_destroy(mem_ctx);
 
-       return result;
+       return status;
 }
 
 /**