root/source4/torture/rpc/dssync.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_create_context
  2. _test_DsBind
  3. test_LDAPBind
  4. test_GetInfo
  5. decrypt_blob
  6. test_analyse_objects
  7. test_FetchData
  8. test_FetchNT4Data
  9. torture_rpc_dssync

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    DsGetNCChanges replication test
   5 
   6    Copyright (C) Stefan (metze) Metzmacher 2005
   7    Copyright (C) Brad Henry 2005
   8    
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "lib/cmdline/popt_common.h"
  25 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
  26 #include "librpc/gen_ndr/ndr_drsblobs.h"
  27 #include "libcli/cldap/cldap.h"
  28 #include "libcli/ldap/ldap_client.h"
  29 #include "torture/torture.h"
  30 #include "torture/ldap/proto.h"
  31 #include "libcli/auth/libcli_auth.h"
  32 #include "../lib/crypto/crypto.h"
  33 #include "auth/credentials/credentials.h"
  34 #include "libcli/auth/libcli_auth.h"
  35 #include "auth/gensec/gensec.h"
  36 #include "param/param.h"
  37 #include "dsdb/samdb/samdb.h"
  38 
  39 struct DsSyncBindInfo {
  40         struct dcerpc_pipe *pipe;
  41         struct drsuapi_DsBind req;
  42         struct GUID bind_guid;
  43         struct drsuapi_DsBindInfoCtr our_bind_info_ctr;
  44         struct drsuapi_DsBindInfo28 our_bind_info28;
  45         struct drsuapi_DsBindInfo28 peer_bind_info28;
  46         struct policy_handle bind_handle;
  47 };
  48 
  49 struct DsSyncLDAPInfo {
  50         struct ldap_connection *conn;
  51 };
  52 
  53 struct DsSyncTest {
  54         struct dcerpc_binding *drsuapi_binding;
  55         
  56         const char *ldap_url;
  57         const char *site_name;
  58         
  59         const char *domain_dn;
  60 
  61         /* what we need to do as 'Administrator' */
  62         struct {
  63                 struct cli_credentials *credentials;
  64                 struct DsSyncBindInfo drsuapi;
  65                 struct DsSyncLDAPInfo ldap;
  66         } admin;
  67 
  68         /* what we need to do as the new dc machine account */
  69         struct {
  70                 struct cli_credentials *credentials;
  71                 struct DsSyncBindInfo drsuapi;
  72                 struct drsuapi_DsGetDCInfo2 dc_info2;
  73                 struct GUID invocation_id;
  74                 struct GUID object_guid;
  75         } new_dc;
  76 
  77         /* info about the old dc */
  78         struct {
  79                 struct drsuapi_DsGetDomainControllerInfo dc_info;
  80         } old_dc;
  81 };
  82 
  83 static struct DsSyncTest *test_create_context(struct torture_context *tctx)
     /* [<][>][^][v][top][bottom][index][help] */
  84 {
  85         NTSTATUS status;
  86         struct DsSyncTest *ctx;
  87         struct drsuapi_DsBindInfo28 *our_bind_info28;
  88         struct drsuapi_DsBindInfoCtr *our_bind_info_ctr;
  89         const char *binding = torture_setting_string(tctx, "binding", NULL);
  90         ctx = talloc_zero(tctx, struct DsSyncTest);
  91         if (!ctx) return NULL;
  92 
  93         status = dcerpc_parse_binding(ctx, binding, &ctx->drsuapi_binding);
  94         if (!NT_STATUS_IS_OK(status)) {
  95                 printf("Bad binding string %s\n", binding);
  96                 return NULL;
  97         }
  98         ctx->drsuapi_binding->flags |= DCERPC_SIGN | DCERPC_SEAL;
  99 
 100         ctx->ldap_url = talloc_asprintf(ctx, "ldap://%s/", ctx->drsuapi_binding->host);
 101 
 102         /* ctx->admin ...*/
 103         ctx->admin.credentials                          = cmdline_credentials;
 104 
 105         our_bind_info28                         = &ctx->admin.drsuapi.our_bind_info28;
 106         our_bind_info28->supported_extensions   = 0xFFFFFFFF;
 107         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
 108         our_bind_info28->site_guid              = GUID_zero();
 109         our_bind_info28->pid                    = 0;
 110         our_bind_info28->repl_epoch             = 1;
 111 
 112         our_bind_info_ctr                       = &ctx->admin.drsuapi.our_bind_info_ctr;
 113         our_bind_info_ctr->length               = 28;
 114         our_bind_info_ctr->info.info28          = *our_bind_info28;
 115 
 116         GUID_from_string(DRSUAPI_DS_BIND_GUID, &ctx->admin.drsuapi.bind_guid);
 117 
 118         ctx->admin.drsuapi.req.in.bind_guid             = &ctx->admin.drsuapi.bind_guid;
 119         ctx->admin.drsuapi.req.in.bind_info             = our_bind_info_ctr;
 120         ctx->admin.drsuapi.req.out.bind_handle          = &ctx->admin.drsuapi.bind_handle;
 121 
 122         /* ctx->new_dc ...*/
 123         ctx->new_dc.credentials                 = cmdline_credentials;
 124 
 125         our_bind_info28                         = &ctx->new_dc.drsuapi.our_bind_info28;
 126         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
 127         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
 128         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
 129         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
 130         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
 131         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
 132         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
 133         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
 134         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
 135         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
 136         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
 137         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
 138         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
 139         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
 140         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
 141         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
 142         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
 143         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
 144         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
 145         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
 146         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
 147         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
 148         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
 149         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
 150         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
 151         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
 152         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
 153         our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
 154         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "xpress", false)) {
 155                 our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
 156         }
 157         our_bind_info28->site_guid              = GUID_zero();
 158         our_bind_info28->pid                    = 0;
 159         our_bind_info28->repl_epoch             = 0;
 160 
 161         our_bind_info_ctr                       = &ctx->new_dc.drsuapi.our_bind_info_ctr;
 162         our_bind_info_ctr->length               = 28;
 163         our_bind_info_ctr->info.info28          = *our_bind_info28;
 164 
 165         GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &ctx->new_dc.drsuapi.bind_guid);
 166 
 167         ctx->new_dc.drsuapi.req.in.bind_guid            = &ctx->new_dc.drsuapi.bind_guid;
 168         ctx->new_dc.drsuapi.req.in.bind_info            = our_bind_info_ctr;
 169         ctx->new_dc.drsuapi.req.out.bind_handle         = &ctx->new_dc.drsuapi.bind_handle;
 170 
 171         ctx->new_dc.invocation_id                       = ctx->new_dc.drsuapi.bind_guid;
 172 
 173         /* ctx->old_dc ...*/
 174 
 175         return ctx;
 176 }
 177 
 178 static bool _test_DsBind(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 179                          struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b)
 180 {
 181         NTSTATUS status;
 182         bool ret = true;
 183 
 184         status = dcerpc_pipe_connect_b(ctx,
 185                                        &b->pipe, ctx->drsuapi_binding, 
 186                                        &ndr_table_drsuapi,
 187                                        credentials, tctx->ev, tctx->lp_ctx);
 188         
 189         if (!NT_STATUS_IS_OK(status)) {
 190                 printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status));
 191                 return false;
 192         }
 193 
 194         status = dcerpc_drsuapi_DsBind(b->pipe, ctx, &b->req);
 195         if (!NT_STATUS_IS_OK(status)) {
 196                 const char *errstr = nt_errstr(status);
 197                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
 198                         errstr = dcerpc_errstr(ctx, b->pipe->last_fault_code);
 199                 }
 200                 printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
 201                 ret = false;
 202         } else if (!W_ERROR_IS_OK(b->req.out.result)) {
 203                 printf("DsBind failed - %s\n", win_errstr(b->req.out.result));
 204                 ret = false;
 205         }
 206 
 207         ZERO_STRUCT(b->peer_bind_info28);
 208         if (b->req.out.bind_info) {
 209                 switch (b->req.out.bind_info->length) {
 210                 case 24: {
 211                         struct drsuapi_DsBindInfo24 *info24;
 212                         info24 = &b->req.out.bind_info->info.info24;
 213                         b->peer_bind_info28.supported_extensions= info24->supported_extensions;
 214                         b->peer_bind_info28.site_guid           = info24->site_guid;
 215                         b->peer_bind_info28.pid                 = info24->pid;
 216                         b->peer_bind_info28.repl_epoch          = 0;
 217                         break;
 218                 }
 219                 case 48: {
 220                         struct drsuapi_DsBindInfo48 *info48;
 221                         info48 = &b->req.out.bind_info->info.info48;
 222                         b->peer_bind_info28.supported_extensions= info48->supported_extensions;
 223                         b->peer_bind_info28.site_guid           = info48->site_guid;
 224                         b->peer_bind_info28.pid                 = info48->pid;
 225                         b->peer_bind_info28.repl_epoch          = info48->repl_epoch;
 226                         break;
 227                 }
 228                 case 28:
 229                         b->peer_bind_info28 = b->req.out.bind_info->info.info28;
 230                         break;
 231                 default:
 232                         printf("DsBind - warning: unknown BindInfo length: %u\n",
 233                                b->req.out.bind_info->length);
 234                 }
 235         }
 236 
 237         return ret;
 238 }
 239 
 240 static bool test_LDAPBind(struct torture_context *tctx, struct DsSyncTest *ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 241                           struct cli_credentials *credentials, struct DsSyncLDAPInfo *l)
 242 {
 243         NTSTATUS status;
 244         bool ret = true;
 245 
 246         status = torture_ldap_connection(tctx, &l->conn, ctx->ldap_url);
 247         if (!NT_STATUS_IS_OK(status)) {
 248                 printf("failed to connect to LDAP: %s\n", ctx->ldap_url);
 249                 return false;
 250         }
 251 
 252         printf("connected to LDAP: %s\n", ctx->ldap_url);
 253 
 254         status = torture_ldap_bind_sasl(l->conn, credentials, tctx->lp_ctx);
 255         if (!NT_STATUS_IS_OK(status)) {
 256                 printf("failed to bind to LDAP:\n");
 257                 return false;
 258         }
 259         printf("bound to LDAP.\n");
 260 
 261         return ret;
 262 }
 263 
 264 static bool test_GetInfo(struct torture_context *tctx, struct DsSyncTest *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 265 {
 266         NTSTATUS status;
 267         struct drsuapi_DsCrackNames r;
 268         union drsuapi_DsNameRequest req;
 269         union drsuapi_DsNameCtr ctr;
 270         int32_t level_out = 0;
 271         struct drsuapi_DsNameString names[1];
 272         bool ret = true;
 273         struct cldap_socket *cldap;
 274         struct cldap_netlogon search;
 275 
 276         cldap = cldap_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
 277 
 278         r.in.bind_handle                = &ctx->admin.drsuapi.bind_handle;
 279         r.in.level                      = 1;
 280         r.in.req                        = &req;
 281         r.in.req->req1.codepage         = 1252; /* western european */
 282         r.in.req->req1.language         = 0x00000407; /* german */
 283         r.in.req->req1.count            = 1;
 284         r.in.req->req1.names            = names;
 285         r.in.req->req1.format_flags     = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
 286         r.in.req->req1.format_offered   = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
 287         r.in.req->req1.format_desired   = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
 288         names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup(tctx->lp_ctx));
 289 
 290         r.out.level_out                 = &level_out;
 291         r.out.ctr                       = &ctr;
 292 
 293         status = dcerpc_drsuapi_DsCrackNames(ctx->admin.drsuapi.pipe, ctx, &r);
 294         if (!NT_STATUS_IS_OK(status)) {
 295                 const char *errstr = nt_errstr(status);
 296                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
 297                         errstr = dcerpc_errstr(ctx, ctx->admin.drsuapi.pipe->last_fault_code);
 298                 }
 299                 printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
 300                 return false;
 301         } else if (!W_ERROR_IS_OK(r.out.result)) {
 302                 printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
 303                 return false;
 304         }
 305 
 306         ctx->domain_dn = r.out.ctr->ctr1->array[0].result_name;
 307         
 308         ZERO_STRUCT(search);
 309         search.in.dest_address = ctx->drsuapi_binding->host;
 310         search.in.dest_port = lp_cldap_port(tctx->lp_ctx);
 311         search.in.acct_control = -1;
 312         search.in.version               = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
 313         search.in.map_response = true;
 314         status = cldap_netlogon(cldap, ctx, &search);
 315         if (!NT_STATUS_IS_OK(status)) {
 316                 const char *errstr = nt_errstr(status);
 317                 ctx->site_name = talloc_asprintf(ctx, "%s", "Default-First-Site-Name");
 318                 printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr, ctx->site_name);          
 319         } else {
 320                 ctx->site_name = talloc_steal(ctx, search.out.netlogon.data.nt5_ex.client_site);
 321                 printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx->site_name);
 322                 printf("cldap_netlogon() returned Server Site-Name: %s.\n",search.out.netlogon.data.nt5_ex.server_site);
 323         }
 324 
 325         if (!ctx->domain_dn) {
 326                 struct ldb_context *ldb = ldb_init(ctx, tctx->ev);
 327                 struct ldb_dn *dn = samdb_dns_domain_to_dn(ldb, ctx, search.out.netlogon.data.nt5_ex.dns_domain);
 328                 ctx->domain_dn = ldb_dn_alloc_linearized(ctx, dn);
 329                 talloc_free(dn);
 330                 talloc_free(ldb);
 331         }
 332 
 333         return ret;
 334 }
 335 
 336 static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 337                               const DATA_BLOB *gensec_skey,
 338                               bool rcrypt,
 339                               struct drsuapi_DsReplicaObjectIdentifier *id,
 340                               uint32_t rid,
 341                               const DATA_BLOB *buffer)
 342 {
 343         DATA_BLOB confounder;
 344         DATA_BLOB enc_buffer;
 345 
 346         struct MD5Context md5;
 347         uint8_t _enc_key[16];
 348         DATA_BLOB enc_key;
 349 
 350         DATA_BLOB dec_buffer;
 351 
 352         uint32_t crc32_given;
 353         uint32_t crc32_calc;
 354         DATA_BLOB checked_buffer;
 355 
 356         DATA_BLOB plain_buffer;
 357 
 358         /*
 359          * the combination "c[3] s[1] e[1] d[0]..."
 360          * was successful!!!!!!!!!!!!!!!!!!!!!!!!!!
 361          */
 362 
 363         /* 
 364          * the first 16 bytes at the beginning are the confounder
 365          * followed by the 4 byte crc32 checksum
 366          */
 367         if (buffer->length < 20) {
 368                 return data_blob_const(NULL, 0);
 369         }
 370         confounder = data_blob_const(buffer->data, 16);
 371         enc_buffer = data_blob_const(buffer->data + 16, buffer->length - 16);
 372 
 373         /* 
 374          * build the encryption key md5 over the session key followed
 375          * by the confounder
 376          * 
 377          * here the gensec session key is used and
 378          * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
 379          */
 380         enc_key = data_blob_const(_enc_key, sizeof(_enc_key));
 381         MD5Init(&md5);
 382         MD5Update(&md5, gensec_skey->data, gensec_skey->length);
 383         MD5Update(&md5, confounder.data, confounder.length);
 384         MD5Final(enc_key.data, &md5);
 385 
 386         /*
 387          * copy the encrypted buffer part and 
 388          * decrypt it using the created encryption key using arcfour
 389          */
 390         dec_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length);
 391         if (!dec_buffer.data) {
 392                 return data_blob_const(NULL, 0);
 393         }
 394         arcfour_crypt_blob(dec_buffer.data, dec_buffer.length, &enc_key);
 395 
 396         /* 
 397          * the first 4 byte are the crc32 checksum
 398          * of the remaining bytes
 399          */
 400         crc32_given = IVAL(dec_buffer.data, 0);
 401         crc32_calc = crc32_calc_buffer(dec_buffer.data + 4 , dec_buffer.length - 4);
 402         if (crc32_given != crc32_calc) {
 403                 DEBUG(0,("CRC32: given[0x%08X] calc[0x%08X]\n",
 404                       crc32_given, crc32_calc));
 405                 return data_blob_const(NULL, 0);
 406         }
 407         checked_buffer = data_blob_talloc(mem_ctx, dec_buffer.data + 4, dec_buffer.length - 4);
 408         if (!checked_buffer.data) {
 409                 return data_blob_const(NULL, 0);
 410         }
 411 
 412         /*
 413          * some attributes seem to be in a usable form after this decryption
 414          * (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing,
 415          *  trustAuthIncoming, initialAuthOutgoing, initialAuthIncoming)
 416          * At least supplementalCredentials contains plaintext
 417          * like "Primary:Kerberos" (in unicode form)
 418          *
 419          * some attributes seem to have some additional encryption
 420          * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
 421          *
 422          * it's the sam_rid_crypt() function, as the value is constant,
 423          * so it doesn't depend on sessionkeys.
 424          */
 425         if (rcrypt) {
 426                 uint32_t i, num_hashes;
 427 
 428                 if ((checked_buffer.length % 16) != 0) {
 429                         return data_blob_const(NULL, 0);
 430                 }
 431 
 432                 plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
 433                 if (!plain_buffer.data) {
 434                         return data_blob_const(NULL, 0);
 435                 }
 436                         
 437                 num_hashes = plain_buffer.length / 16;
 438                 for (i = 0; i < num_hashes; i++) {
 439                         uint32_t offset = i * 16;
 440                         sam_rid_crypt(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0);
 441                 }
 442         } else {
 443                 plain_buffer = checked_buffer;
 444         }
 445 
 446         return plain_buffer;
 447 }
 448 
 449 static void test_analyse_objects(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 450                                  struct DsSyncTest *ctx,
 451                                  const DATA_BLOB *gensec_skey,
 452                                  struct drsuapi_DsReplicaObjectListItemEx *cur)
 453 {
 454         static uint32_t object_id;
 455         const char *save_values_dir;
 456 
 457         if (!lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) {
 458                 return; 
 459         }
 460 
 461         save_values_dir = lp_parm_string(tctx->lp_ctx, NULL, "dssync", "save_pwd_blobs_dir");
 462 
 463         for (; cur; cur = cur->next_object) {
 464                 const char *dn;
 465                 struct dom_sid *sid = NULL;
 466                 uint32_t rid = 0;
 467                 bool dn_printed = false;
 468                 uint32_t i;
 469 
 470                 if (!cur->object.identifier) continue;
 471 
 472                 dn = cur->object.identifier->dn;
 473                 if (cur->object.identifier->sid.num_auths > 0) {
 474                         sid = &cur->object.identifier->sid;
 475                         rid = sid->sub_auths[sid->num_auths - 1];
 476                 }
 477 
 478                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
 479                         const char *name = NULL;
 480                         bool rcrypt = false;
 481                         DATA_BLOB *enc_data = NULL;
 482                         DATA_BLOB plain_data;
 483                         struct drsuapi_DsReplicaAttribute *attr;
 484                         ndr_pull_flags_fn_t pull_fn = NULL;
 485                         ndr_print_fn_t print_fn = NULL;
 486                         void *ptr = NULL;
 487                         attr = &cur->object.attribute_ctr.attributes[i];
 488 
 489                         switch (attr->attid) {
 490                         case DRSUAPI_ATTRIBUTE_dBCSPwd:
 491                                 name    = "dBCSPwd";
 492                                 rcrypt  = true;
 493                                 break;
 494                         case DRSUAPI_ATTRIBUTE_unicodePwd:
 495                                 name    = "unicodePwd";
 496                                 rcrypt  = true;
 497                                 break;
 498                         case DRSUAPI_ATTRIBUTE_ntPwdHistory:
 499                                 name    = "ntPwdHistory";
 500                                 rcrypt  = true;
 501                                 break;
 502                         case DRSUAPI_ATTRIBUTE_lmPwdHistory:
 503                                 name    = "lmPwdHistory";
 504                                 rcrypt  = true;
 505                                 break;
 506                         case DRSUAPI_ATTRIBUTE_supplementalCredentials:
 507                                 name    = "supplementalCredentials";
 508                                 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob;
 509                                 print_fn = (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob;
 510                                 ptr = talloc(ctx, struct supplementalCredentialsBlob);
 511                                 break;
 512                         case DRSUAPI_ATTRIBUTE_priorValue:
 513                                 name    = "priorValue";
 514                                 break;
 515                         case DRSUAPI_ATTRIBUTE_currentValue:
 516                                 name    = "currentValue";
 517                                 break;
 518                         case DRSUAPI_ATTRIBUTE_trustAuthOutgoing:
 519                                 name    = "trustAuthOutgoing";
 520                                 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob;
 521                                 print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob;
 522                                 ptr = talloc(ctx, struct trustAuthInOutBlob);
 523                                 break;
 524                         case DRSUAPI_ATTRIBUTE_trustAuthIncoming:
 525                                 name    = "trustAuthIncoming";
 526                                 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob;
 527                                 print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob;
 528                                 ptr = talloc(ctx, struct trustAuthInOutBlob);
 529                                 break;
 530                         case DRSUAPI_ATTRIBUTE_initialAuthOutgoing:
 531                                 name    = "initialAuthOutgoing";
 532                                 break;
 533                         case DRSUAPI_ATTRIBUTE_initialAuthIncoming:
 534                                 name    = "initialAuthIncoming";
 535                                 break;
 536                         default:
 537                                 continue;
 538                         }
 539 
 540                         if (attr->value_ctr.num_values != 1) continue;
 541 
 542                         if (!attr->value_ctr.values[0].blob) continue;
 543 
 544                         enc_data = attr->value_ctr.values[0].blob;
 545                         ZERO_STRUCT(plain_data);
 546 
 547                         plain_data = decrypt_blob(ctx, gensec_skey, rcrypt,
 548                                                   cur->object.identifier, rid,
 549                                                   enc_data);
 550                         if (!dn_printed) {
 551                                 object_id++;
 552                                 DEBUG(0,("DN[%u] %s\n", object_id, dn));
 553                                 dn_printed = true;
 554                         }
 555                         DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
 556                                     name, (long)enc_data->length, (long)plain_data.length));
 557                         if (plain_data.length) {
 558                                 enum ndr_err_code ndr_err;
 559                                 dump_data(0, plain_data.data, plain_data.length);
 560                                 if (save_values_dir) {
 561                                         char *fname;
 562                                         fname = talloc_asprintf(ctx, "%s/%s%02d",
 563                                                                 save_values_dir,
 564                                                                 name, object_id);
 565                                         if (fname) {
 566                                                 bool ok;
 567                                                 ok = file_save(fname, plain_data.data, plain_data.length);
 568                                                 if (!ok) {
 569                                                         DEBUGADD(0,("Failed to save '%s'\n", fname));
 570                                                 }
 571                                         }
 572                                         talloc_free(fname);
 573                                 }
 574 
 575                                 if (pull_fn) {
 576                                         /* Can't use '_all' because of PIDL bugs with relative pointers */
 577                                         ndr_err = ndr_pull_struct_blob(&plain_data, ptr,
 578                                                                        lp_iconv_convenience(tctx->lp_ctx), ptr,
 579                                                                        pull_fn);
 580                                         if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 581                                                 ndr_print_debug(print_fn, name, ptr);
 582                                         } else {
 583                                                 DEBUG(0, ("Failed to decode %s\n", name));
 584                                         }
 585                                 }
 586                         } else {
 587                                 dump_data(0, enc_data->data, enc_data->length);
 588                         }
 589                         talloc_free(ptr);
 590                 }
 591         }
 592 }
 593 
 594 static bool test_FetchData(struct torture_context *tctx, struct DsSyncTest *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 595 {
 596         NTSTATUS status;
 597         bool ret = true;
 598         int i, y = 0;
 599         uint64_t highest_usn = 0;
 600         const char *partition = NULL;
 601         struct drsuapi_DsGetNCChanges r;
 602         union drsuapi_DsGetNCChangesRequest req;
 603         struct drsuapi_DsReplicaObjectIdentifier nc;
 604         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
 605         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
 606         int32_t out_level = 0;
 607         struct GUID null_guid;
 608         struct dom_sid null_sid;
 609         DATA_BLOB gensec_skey;
 610         struct {
 611                 int32_t level;
 612         } array[] = {
 613 /*              {
 614                         5
 615                 },
 616 */              {
 617                         8
 618                 }
 619         };
 620 
 621         ZERO_STRUCT(null_guid);
 622         ZERO_STRUCT(null_sid);
 623 
 624         partition = lp_parm_string(tctx->lp_ctx, NULL, "dssync", "partition");
 625         if (partition == NULL) {
 626                 partition = ctx->domain_dn;
 627                 printf("dssync:partition not specified, defaulting to %s.\n", ctx->domain_dn);
 628         }
 629 
 630         highest_usn = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "highest_usn", 0);
 631 
 632         array[0].level = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "get_nc_changes_level", array[0].level);
 633 
 634         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) {
 635                 const struct samr_Password *nthash;
 636                 nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx);
 637                 if (nthash) {
 638                         dump_data_pw("CREDENTIALS nthash:", nthash->hash, sizeof(nthash->hash));
 639                 }
 640         }
 641         status = gensec_session_key(ctx->new_dc.drsuapi.pipe->conn->security_state.generic_state,
 642                                     &gensec_skey);
 643         if (!NT_STATUS_IS_OK(status)) {
 644                 printf("failed to get gensec session key: %s\n", nt_errstr(status));
 645                 return false;
 646         }
 647 
 648         for (i=0; i < ARRAY_SIZE(array); i++) {
 649                 printf("testing DsGetNCChanges level %d\n",
 650                         array[i].level);
 651 
 652                 r.in.bind_handle        = &ctx->new_dc.drsuapi.bind_handle;
 653                 r.in.level              = array[i].level;
 654 
 655                 switch (r.in.level) {
 656                 case 5:
 657                         nc.guid = null_guid;
 658                         nc.sid  = null_sid;
 659                         nc.dn   = partition; 
 660 
 661                         r.in.req                                        = &req;
 662                         r.in.req->req5.destination_dsa_guid             = ctx->new_dc.invocation_id;
 663                         r.in.req->req5.source_dsa_invocation_id         = null_guid;
 664                         r.in.req->req5.naming_context                   = &nc;
 665                         r.in.req->req5.highwatermark.tmp_highest_usn    = highest_usn;
 666                         r.in.req->req5.highwatermark.reserved_usn       = 0;
 667                         r.in.req->req5.highwatermark.highest_usn        = highest_usn;
 668                         r.in.req->req5.uptodateness_vector              = NULL;
 669                         r.in.req->req5.replica_flags                    = 0;
 670                         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) {
 671                                 r.in.req->req5.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
 672                         }
 673                         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) {
 674                                 r.in.req->req5.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
 675                         }
 676                         r.in.req->req5.replica_flags                    |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
 677                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
 678                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
 679                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
 680                                                                         ;
 681                         r.in.req->req5.max_object_count                 = 133;
 682                         r.in.req->req5.max_ndr_size                     = 1336770;
 683                         r.in.req->req5.extended_op                      = DRSUAPI_EXOP_NONE;
 684                         r.in.req->req5.fsmo_info                        = 0;
 685 
 686                         break;
 687                 case 8:
 688                         nc.guid = null_guid;
 689                         nc.sid  = null_sid;
 690                         nc.dn   = partition; 
 691                         /* nc.dn can be set to any other ad partition */
 692 
 693                         r.in.req                                        = &req;
 694                         r.in.req->req8.destination_dsa_guid             = ctx->new_dc.invocation_id;
 695                         r.in.req->req8.source_dsa_invocation_id         = null_guid;
 696                         r.in.req->req8.naming_context                   = &nc;
 697                         r.in.req->req8.highwatermark.tmp_highest_usn    = highest_usn;
 698                         r.in.req->req8.highwatermark.reserved_usn       = 0;
 699                         r.in.req->req8.highwatermark.highest_usn        = highest_usn;
 700                         r.in.req->req8.uptodateness_vector              = NULL;
 701                         r.in.req->req8.replica_flags                    = 0;
 702                         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) {
 703                                 r.in.req->req8.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
 704                         }
 705                         if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) {
 706                                 r.in.req->req8.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
 707                         }
 708                         r.in.req->req8.replica_flags                    |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
 709                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
 710                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
 711                                                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
 712                                                                         ;
 713                         r.in.req->req8.max_object_count                 = 402;
 714                         r.in.req->req8.max_ndr_size                     = 402116;
 715 
 716                         r.in.req->req8.extended_op                      = DRSUAPI_EXOP_NONE;
 717                         r.in.req->req8.fsmo_info                        = 0;
 718                         r.in.req->req8.partial_attribute_set            = NULL;
 719                         r.in.req->req8.partial_attribute_set_ex         = NULL;
 720                         r.in.req->req8.mapping_ctr.num_mappings         = 0;
 721                         r.in.req->req8.mapping_ctr.mappings             = NULL;
 722 
 723                         break;
 724                 }
 725                 
 726                 printf("Dumping AD partition: %s\n", nc.dn);
 727                 for (y=0; ;y++) {
 728                         int32_t _level = 0;
 729                         union drsuapi_DsGetNCChangesCtr ctr;
 730 
 731                         ZERO_STRUCT(r.out);
 732 
 733                         r.out.level_out = &_level;
 734                         r.out.ctr       = &ctr;
 735 
 736                         if (r.in.level == 5) {
 737                                 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
 738                                         (long long)r.in.req->req5.highwatermark.tmp_highest_usn,
 739                                         (long long)r.in.req->req5.highwatermark.highest_usn));
 740                         }
 741 
 742                         if (r.in.level == 8) {
 743                                 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
 744                                         (long long)r.in.req->req8.highwatermark.tmp_highest_usn,
 745                                         (long long)r.in.req->req8.highwatermark.highest_usn));
 746                         }
 747 
 748                         status = dcerpc_drsuapi_DsGetNCChanges(ctx->new_dc.drsuapi.pipe, ctx, &r);
 749                         if (!NT_STATUS_IS_OK(status)) {
 750                                 const char *errstr = nt_errstr(status);
 751                                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
 752                                         errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code);
 753                                 }
 754                                 printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr);
 755                                 ret = false;
 756                         } else if (!W_ERROR_IS_OK(r.out.result)) {
 757                                 printf("DsGetNCChanges failed - %s\n", win_errstr(r.out.result));
 758                                 ret = false;
 759                         }
 760 
 761                         if (ret == true && *r.out.level_out == 1) {
 762                                 out_level = 1;
 763                                 ctr1 = &r.out.ctr->ctr1;
 764                         } else if (ret == true && *r.out.level_out == 2 &&
 765                                    r.out.ctr->ctr2.mszip1.ts) {
 766                                 out_level = 1;
 767                                 ctr1 = &r.out.ctr->ctr2.mszip1.ts->ctr1;
 768                         }
 769 
 770                         if (out_level == 1) {
 771                                 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
 772                                         (long long)ctr1->new_highwatermark.tmp_highest_usn,
 773                                         (long long)ctr1->new_highwatermark.highest_usn));
 774 
 775                                 test_analyse_objects(tctx, ctx, &gensec_skey, ctr1->first_object);
 776 
 777                                 if (ctr1->more_data) {
 778                                         r.in.req->req5.highwatermark = ctr1->new_highwatermark;
 779                                         continue;
 780                                 }
 781                         }
 782 
 783                         if (ret == true && *r.out.level_out == 6) {
 784                                 out_level = 6;
 785                                 ctr6 = &r.out.ctr->ctr6;
 786                         } else if (ret == true && *r.out.level_out == 7
 787                                    && r.out.ctr->ctr7.level == 6
 788                                    && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP
 789                                    && r.out.ctr->ctr7.ctr.mszip6.ts) {
 790                                 out_level = 6;
 791                                 ctr6 = &r.out.ctr->ctr7.ctr.mszip6.ts->ctr6;
 792                         } else if (ret == true && *r.out.level_out == 7
 793                                    && r.out.ctr->ctr7.level == 6
 794                                    && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS
 795                                    && r.out.ctr->ctr7.ctr.xpress6.ts) {
 796                                 out_level = 6;
 797                                 ctr6 = &r.out.ctr->ctr7.ctr.xpress6.ts->ctr6;
 798                         }
 799 
 800                         if (out_level == 6) {
 801                                 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
 802                                         (long long)ctr6->new_highwatermark.tmp_highest_usn,
 803                                         (long long)ctr6->new_highwatermark.highest_usn));
 804 
 805                                 test_analyse_objects(tctx, ctx, &gensec_skey, ctr6->first_object);
 806 
 807                                 if (ctr6->more_data) {
 808                                         r.in.req->req8.highwatermark = ctr6->new_highwatermark;
 809                                         continue;
 810                                 }
 811                         }
 812 
 813                         break;
 814                 }
 815         }
 816 
 817         return ret;
 818 }
 819 
 820 static bool test_FetchNT4Data(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 821                               struct DsSyncTest *ctx)
 822 {
 823         NTSTATUS status;
 824         bool ret = true;
 825         struct drsuapi_DsGetNT4ChangeLog r;
 826         union drsuapi_DsGetNT4ChangeLogRequest req;
 827         union drsuapi_DsGetNT4ChangeLogInfo info;
 828         uint32_t level_out = 0;
 829         struct GUID null_guid;
 830         struct dom_sid null_sid;
 831         DATA_BLOB cookie;
 832 
 833         ZERO_STRUCT(null_guid);
 834         ZERO_STRUCT(null_sid);
 835         ZERO_STRUCT(cookie);
 836 
 837         ZERO_STRUCT(r);
 838         r.in.bind_handle        = &ctx->new_dc.drsuapi.bind_handle;
 839         r.in.level              = 1;
 840         r.out.info              = &info;
 841         r.out.level_out         = &level_out;
 842 
 843         req.req1.unknown1       = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "nt4-1", 3);
 844         req.req1.unknown2       = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "nt4-2", 0x00004000);
 845 
 846         while (1) {
 847                 req.req1.length = cookie.length;
 848                 req.req1.data   = cookie.data;
 849 
 850                 r.in.req = &req;
 851 
 852                 status = dcerpc_drsuapi_DsGetNT4ChangeLog(ctx->new_dc.drsuapi.pipe, ctx, &r);
 853                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
 854                         printf("DsGetNT4ChangeLog not supported by target server\n");
 855                         break;
 856                 } else if (!NT_STATUS_IS_OK(status)) {
 857                         const char *errstr = nt_errstr(status);
 858                         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
 859                                 errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code);
 860                         }
 861                         printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr);
 862                         ret = false;
 863                 } else if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_DOMAIN_ROLE)) {
 864                         printf("DsGetNT4ChangeLog not supported by target server\n");
 865                         break;
 866                 } else if (!W_ERROR_IS_OK(r.out.result)) {
 867                         printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r.out.result));
 868                         ret = false;
 869                 } else if (*r.out.level_out != 1) {
 870                         printf("DsGetNT4ChangeLog unknown level - %u\n", *r.out.level_out);
 871                         ret = false;
 872                 } else if (NT_STATUS_IS_OK(r.out.info->info1.status)) {
 873                 } else if (NT_STATUS_EQUAL(r.out.info->info1.status, STATUS_MORE_ENTRIES)) {
 874                         cookie.length   = r.out.info->info1.length1;
 875                         cookie.data     = r.out.info->info1.data1;
 876                         continue;
 877                 } else {
 878                         printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r.out.info->info1.status));
 879                         ret = false;
 880                 }
 881 
 882                 break;
 883         }
 884 
 885         return ret;
 886 }
 887 
 888 bool torture_rpc_dssync(struct torture_context *torture)
     /* [<][>][^][v][top][bottom][index][help] */
 889 {
 890         bool ret = true;
 891         TALLOC_CTX *mem_ctx;
 892         struct DsSyncTest *ctx;
 893         
 894         mem_ctx = talloc_init("torture_rpc_dssync");
 895         ctx = test_create_context(torture);
 896         
 897         ret &= _test_DsBind(torture, ctx, ctx->admin.credentials, &ctx->admin.drsuapi);
 898         if (!ret) {
 899                 return ret;
 900         }
 901         ret &= test_LDAPBind(torture, ctx, ctx->admin.credentials, &ctx->admin.ldap);
 902         if (!ret) {
 903                 return ret;
 904         }
 905         ret &= test_GetInfo(torture, ctx);
 906         ret &= _test_DsBind(torture, ctx, ctx->new_dc.credentials, &ctx->new_dc.drsuapi);
 907         if (!ret) {
 908                 return ret;
 909         }
 910         ret &= test_FetchData(torture, ctx);
 911         ret &= test_FetchNT4Data(torture, ctx);
 912 
 913         return ret;
 914 }

/* [<][>][^][v][top][bottom][index][help] */