This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "auth/credentials/credentials.h"
#include "libcli/auth/libcli_auth.h"
#include "auth/gensec/gensec.h"
+#include "param/param.h"
struct DsSyncBindInfo {
struct dcerpc_pipe *pipe;
struct DsSyncTest *ctx;
struct drsuapi_DsBindInfo28 *our_bind_info28;
struct drsuapi_DsBindInfoCtr *our_bind_info_ctr;
- const char *binding = lp_parm_string(-1, "torture", "binding");
+ const char *binding = lp_parm_string(global_loadparm, NULL, "torture", "binding");
ctx = talloc_zero(mem_ctx, struct DsSyncTest);
if (!ctx) return NULL;
our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
- if (lp_parm_bool(-1,"dssync","xpress",False)) {
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "xpress", false)) {
our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
}
our_bind_info28->site_guid = GUID_zero();
return ctx;
}
-static BOOL _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b)
+static bool _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b)
{
NTSTATUS status;
- BOOL ret = True;
+ bool ret = true;
struct event_context *event = NULL;
status = dcerpc_pipe_connect_b(ctx,
&b->pipe, ctx->drsuapi_binding,
- &dcerpc_table_drsuapi,
+ &ndr_table_drsuapi,
credentials, event);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status));
- return False;
+ return false;
}
status = dcerpc_drsuapi_DsBind(b->pipe, ctx, &b->req);
errstr = dcerpc_errstr(ctx, b->pipe->last_fault_code);
}
printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
- ret = False;
+ ret = false;
} else if (!W_ERROR_IS_OK(b->req.out.result)) {
printf("DsBind failed - %s\n", win_errstr(b->req.out.result));
- ret = False;
+ ret = false;
}
ZERO_STRUCT(b->peer_bind_info28);
return ret;
}
-static BOOL test_LDAPBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncLDAPInfo *l)
+static bool test_LDAPBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncLDAPInfo *l)
{
NTSTATUS status;
- BOOL ret = True;
+ bool ret = true;
status = torture_ldap_connection(ctx, &l->conn, ctx->ldap_url);
if (!NT_STATUS_IS_OK(status)) {
printf("failed to connect to LDAP: %s\n", ctx->ldap_url);
- return False;
+ return false;
}
printf("connected to LDAP: %s\n", ctx->ldap_url);
status = torture_ldap_bind_sasl(l->conn, credentials);
if (!NT_STATUS_IS_OK(status)) {
printf("failed to bind to LDAP:\n");
- return False;
+ return false;
}
printf("bound to LDAP.\n");
return ret;
}
-static BOOL test_GetInfo(struct DsSyncTest *ctx)
+static bool test_GetInfo(struct DsSyncTest *ctx)
{
NTSTATUS status;
struct drsuapi_DsCrackNames r;
struct drsuapi_DsNameString names[1];
- BOOL ret = True;
+ bool ret = true;
struct cldap_socket *cldap = cldap_socket_init(ctx, NULL);
struct cldap_netlogon search;
r.in.req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup());
+ names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup(global_loadparm));
status = dcerpc_drsuapi_DsCrackNames(ctx->admin.drsuapi.pipe, ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
errstr = dcerpc_errstr(ctx, ctx->admin.drsuapi.pipe->last_fault_code);
}
printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
- return False;
+ return false;
} else if (!W_ERROR_IS_OK(r.out.result)) {
printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
- return False;
+ return false;
}
ctx->domain_dn = r.out.ctr.ctr1->array[0].result_name;
return ret;
}
-static void sam_rid_crypt_len(uint_t rid, uint32_t len, const uint8_t *in, uint8_t *out, int forw)
-{
- uint8_t s[14];
- uint8_t in_pad[8], out_pad[8];
- uint32_t b_off, s_off = 0;
-
- s[0] = s[4] = s[8] = s[12] = (uint8_t)(rid & 0xFF);
- s[1] = s[5] = s[9] = s[13] = (uint8_t)((rid >> 8) & 0xFF);
- s[2] = s[6] = s[10] = (uint8_t)((rid >> 16) & 0xFF);
- s[3] = s[7] = s[11] = (uint8_t)((rid >> 24) & 0xFF);
-
- for (b_off=0; b_off < len; b_off += 8) {
- uint32_t left = len - b_off;
- if (left >= 8) {
- des_crypt56(out + b_off, in + b_off, s + s_off, forw);
- } else {
- ZERO_STRUCT(in_pad);
- memcpy(in_pad, in + b_off, left);
- des_crypt56(out_pad, in + b_off, s + s_off, forw);
- memcpy(out + b_off, out_pad, left);
- ZERO_STRUCT(out_pad);
- }
- if (s_off == 0) {
- s_off = 7;
- } else {
- s_off--;
- }
- }
-}
-
static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx,
const DATA_BLOB *gensec_skey,
bool rcrypt,
DATA_BLOB enc_key;
DATA_BLOB dec_buffer;
+
+ uint32_t crc32_given;
+ uint32_t crc32_calc;
+ DATA_BLOB checked_buffer;
+
DATA_BLOB plain_buffer;
/*
* was successful!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
- /* the first 16 bytes at the beginning are the confounder */
- if (buffer->length <= 16) {
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+ if (buffer->length < 20) {
return data_blob_const(NULL, 0);
}
confounder = data_blob_const(buffer->data, 16);
}
arcfour_crypt_blob(dec_buffer.data, dec_buffer.length, &enc_key);
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_given = IVAL(dec_buffer.data, 0);
+ crc32_calc = crc32_calc_buffer(dec_buffer.data + 4 , dec_buffer.length - 4);
+ if (crc32_given != crc32_calc) {
+ DEBUG(0,("CRC32: given[0x%08X] calc[0x%08X]\n",
+ crc32_given, crc32_calc));
+ return data_blob_const(NULL, 0);
+ }
+ checked_buffer = data_blob_talloc(mem_ctx, dec_buffer.data + 4, dec_buffer.length - 4);
+ if (!checked_buffer.data) {
+ return data_blob_const(NULL, 0);
+ }
+
/*
* some attributes seem to be in a usable form after this decryption
* (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing,
* dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
*
* it's the sam_rid_crypt() function, as the value is constant,
- * so it doesn't depend on sessionkeys. But for the unicodePwd attribute
- * which contains the nthash has 20 bytes at this point.
- *
- * the first 4 byte are unknown yet, but the last 16 byte are the
- * rid crypted hash.
+ * so it doesn't depend on sessionkeys.
*/
if (rcrypt) {
- plain_buffer = data_blob_talloc(mem_ctx, dec_buffer.data, dec_buffer.length);
- if (!plain_buffer.data) {
+ uint32_t i, num_hashes;
+
+ if ((checked_buffer.length % 16) != 0) {
return data_blob_const(NULL, 0);
}
- if (plain_buffer.length < 20) {
+
+ plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
+ if (!plain_buffer.data) {
return data_blob_const(NULL, 0);
}
- /*
- * TODO: check if that's correct for the history fields,
- * which can be larger than 16 bytes (but in 16 byte steps)
- * maybe we need to call the 16 byte sam_rid_crypt() function
- * for each hash, but here we assume the rid des key is shifted
- * by one for each 8 byte block.
- */
- sam_rid_crypt_len(rid, dec_buffer.length - 4, dec_buffer.data + 4, plain_buffer.data + 4, 0);
+
+ num_hashes = plain_buffer.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ sam_rid_crypt(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0);
+ }
} else {
- plain_buffer = dec_buffer;
+ plain_buffer = checked_buffer;
}
return plain_buffer;
const DATA_BLOB *gensec_skey,
struct drsuapi_DsReplicaObjectListItemEx *cur)
{
- if (!lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) {
+ static uint32_t object_id;
+ const char *save_values_dir;
+
+ if (!lp_parm_bool(global_loadparm, NULL,"dssync","print_pwd_blobs", false)) {
return;
}
+ save_values_dir = lp_parm_string(global_loadparm, NULL, "dssync", "save_pwd_blobs_dir");
+
for (; cur; cur = cur->next_object) {
const char *dn;
struct dom_sid *sid = NULL;
uint32_t rid = 0;
- BOOL dn_printed = False;
+ bool dn_printed = false;
uint32_t i;
if (!cur->object.identifier) continue;
cur->object.identifier, rid,
enc_data);
if (!dn_printed) {
- DEBUG(0,("DN: %s\n", dn));
- dn_printed = True;
+ object_id++;
+ DEBUG(0,("DN[%u] %s\n", object_id, dn));
+ dn_printed = true;
}
DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
name, (long)enc_data->length, (long)plain_data.length));
if (plain_data.length) {
dump_data(0, plain_data.data, plain_data.length);
+ if (save_values_dir) {
+ char *fname;
+ fname = talloc_asprintf(ctx, "%s/%s%02d",
+ save_values_dir,
+ name, object_id);
+ if (fname) {
+ bool ok;
+ ok = file_save(fname, plain_data.data, plain_data.length);
+ if (!ok) {
+ DEBUGADD(0,("Failed to save '%s'\n", fname));
+ }
+ }
+ talloc_free(fname);
+ }
} else {
dump_data(0, enc_data->data, enc_data->length);
}
}
}
-static BOOL test_FetchData(struct DsSyncTest *ctx)
+static bool test_FetchData(struct DsSyncTest *ctx)
{
NTSTATUS status;
- BOOL ret = True;
+ bool ret = true;
int i, y = 0;
uint64_t highest_usn = 0;
const char *partition = NULL;
ZERO_STRUCT(null_guid);
ZERO_STRUCT(null_sid);
- partition = lp_parm_string(-1, "dssync", "partition");
+ partition = lp_parm_string(global_loadparm, NULL, "dssync", "partition");
if (partition == NULL) {
partition = ctx->domain_dn;
printf("dssync:partition not specified, defaulting to %s.\n", ctx->domain_dn);
}
- highest_usn = lp_parm_int(-1, "dssync", "highest_usn", 0);
+ highest_usn = lp_parm_int(global_loadparm, NULL, "dssync", "highest_usn", 0);
- if (lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) {
+ array[0].level = lp_parm_int(global_loadparm, NULL, "dssync", "get_nc_changes_level", array[0].level);
+
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "print_pwd_blobs", false)) {
const struct samr_Password *nthash;
nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx);
if (nthash) {
&gensec_skey);
if (!NT_STATUS_IS_OK(status)) {
printf("failed to get gensec session key: %s\n", nt_errstr(status));
- return False;
+ return false;
}
for (i=0; i < ARRAY_SIZE(array); i++) {
r.in.req.req5.highwatermark.highest_usn = highest_usn;
r.in.req.req5.uptodateness_vector = NULL;
r.in.req.req5.replica_flags = 0;
- if (lp_parm_bool(-1,"dssync","compression",False)) {
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "compression", false)) {
r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
}
- if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) {
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "neighbour_writeable", true)) {
r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
}
r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
r.in.req.req8.highwatermark.highest_usn = highest_usn;
r.in.req.req8.uptodateness_vector = NULL;
r.in.req.req8.replica_flags = 0;
- if (lp_parm_bool(-1,"dssync","compression",False)) {
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "compression", false)) {
r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
}
- if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) {
+ if (lp_parm_bool(global_loadparm, NULL, "dssync", "neighbour_writeable", true)) {
r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
}
r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code);
}
printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr);
- ret = False;
+ ret = false;
} else if (!W_ERROR_IS_OK(r.out.result)) {
printf("DsGetNCChanges failed - %s\n", win_errstr(r.out.result));
- ret = False;
+ ret = false;
}
- if (ret == True && *r.out.level == 1) {
+ if (ret == true && *r.out.level == 1) {
out_level = 1;
ctr1 = &r.out.ctr.ctr1;
- } else if (ret == True && *r.out.level == 2) {
+ } else if (ret == true && *r.out.level == 2) {
out_level = 1;
ctr1 = r.out.ctr.ctr2.ctr.mszip1.ctr1;
}
}
}
- if (ret == True && *r.out.level == 6) {
+ if (ret == true && *r.out.level == 6) {
out_level = 6;
ctr6 = &r.out.ctr.ctr6;
- } else if (ret == True && *r.out.level == 7
+ } else if (ret == true && *r.out.level == 7
&& r.out.ctr.ctr7.level == 6
&& r.out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
out_level = 6;
return ret;
}
-static BOOL test_FetchNT4Data(struct DsSyncTest *ctx)
+static bool test_FetchNT4Data(struct DsSyncTest *ctx)
{
NTSTATUS status;
- BOOL ret = True;
- int i, y = 0;
- uint64_t highest_usn = 0;
- const char *partition = NULL;
+ bool ret = true;
struct drsuapi_DsGetNT4ChangeLog r;
- int32_t out_level = 0;
struct GUID null_guid;
struct dom_sid null_sid;
DATA_BLOB cookie;
r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle;
r.in.level = 1;
- r.in.req.req1.unknown1 = lp_parm_int(-1, "dssync", "nt4-1", 3);
- r.in.req.req1.unknown2 = lp_parm_int(-1, "dssync", "nt4-2", 0x00004000);
+ r.in.req.req1.unknown1 = lp_parm_int(global_loadparm, NULL, "dssync", "nt4-1", 3);
+ r.in.req.req1.unknown2 = lp_parm_int(global_loadparm, NULL, "dssync", "nt4-2", 0x00004000);
while (1) {
r.in.req.req1.length = cookie.length;
errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code);
}
printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr);
- ret = False;
+ ret = false;
+ } else if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_DOMAIN_ROLE)) {
+ printf("DsGetNT4ChangeLog not supported by target server\n");
+ break;
} else if (!W_ERROR_IS_OK(r.out.result)) {
printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r.out.result));
- ret = False;
+ ret = false;
} else if (r.out.level != 1) {
printf("DsGetNT4ChangeLog unknown level - %u\n", r.out.level);
- ret = False;
+ ret = false;
} else if (NT_STATUS_IS_OK(r.out.info.info1.status)) {
} else if (NT_STATUS_EQUAL(r.out.info.info1.status, STATUS_MORE_ENTRIES)) {
cookie.length = r.out.info.info1.length1;
continue;
} else {
printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r.out.info.info1.status));
- ret = False;
+ ret = false;
}
break;
return ret;
}
-BOOL torture_rpc_dssync(struct torture_context *torture)
+bool torture_rpc_dssync(struct torture_context *torture)
{
- BOOL ret = True;
+ bool ret = true;
TALLOC_CTX *mem_ctx;
struct DsSyncTest *ctx;
ctx = test_create_context(mem_ctx);
ret &= _test_DsBind(ctx, ctx->admin.credentials, &ctx->admin.drsuapi);
+ if (!ret) {
+ return ret;
+ }
ret &= test_LDAPBind(ctx, ctx->admin.credentials, &ctx->admin.ldap);
+ if (!ret) {
+ return ret;
+ }
ret &= test_GetInfo(ctx);
ret &= _test_DsBind(ctx, ctx->new_dc.credentials, &ctx->new_dc.drsuapi);
+ if (!ret) {
+ return ret;
+ }
ret &= test_FetchData(ctx);
ret &= test_FetchNT4Data(ctx);