diff options
Diffstat (limited to 'source4')
38 files changed, 1326 insertions, 387 deletions
diff --git a/source4/dsdb/common/flags.h b/source4/dsdb/common/flags.h index 36111418e2..e8802fdf9c 100644 --- a/source4/dsdb/common/flags.h +++ b/source4/dsdb/common/flags.h @@ -122,3 +122,4 @@  #define DS_BEHAVIOR_WIN2000		0  #define DS_BEHAVIOR_WIN2003_INTERIM	1  #define DS_BEHAVIOR_WIN2003		2 +#define DS_BEHAVIOR_WIN2008		3 diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index 281e5691e2..345e3db1ab 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -142,10 +142,19 @@ static void dreplsrv_out_drsuapi_bind_recv(struct rpc_request *req)  			info24 = &st->bind_r.out.bind_info->info.info24;  			st->drsuapi->remote_info28.supported_extensions	= info24->supported_extensions;  			st->drsuapi->remote_info28.site_guid		= info24->site_guid; -			st->drsuapi->remote_info28.u1			= info24->u1; +			st->drsuapi->remote_info28.pid			= info24->pid;  			st->drsuapi->remote_info28.repl_epoch		= 0;  			break;  		} +		case 48: { +			struct drsuapi_DsBindInfo48 *info48; +			info48 = &st->bind_r.out.bind_info->info.info48; +			st->drsuapi->remote_info28.supported_extensions	= info48->supported_extensions; +			st->drsuapi->remote_info28.site_guid		= info48->site_guid; +			st->drsuapi->remote_info28.pid			= info48->pid; +			st->drsuapi->remote_info28.repl_epoch		= info48->repl_epoch; +			break; +		}  		case 28:  			st->drsuapi->remote_info28 = st->bind_r.out.bind_info->info.info28;  			break; diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c index e485c50a47..3611258ca5 100644 --- a/source4/dsdb/repl/drepl_service.c +++ b/source4/dsdb/repl/drepl_service.c @@ -104,7 +104,7 @@ static WERROR dreplsrv_connect_samdb(struct dreplsrv_service *service, struct lo  	/* TODO: fill in site_guid */  	bind_info28->site_guid			= GUID_zero();  	/* TODO: find out how this is really triggered! */ -	bind_info28->u1				= 0; +	bind_info28->pid			= 0;  	bind_info28->repl_epoch			= 0;  	return WERR_OK; diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 22826e4f33..9285d6d0d8 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -699,6 +699,50 @@ static int partition_extended_replicated_objects(struct ldb_module *module, stru  	return partition_replicate(module, req, ext->partition_dn);  } +static int partition_extended_schema_update_now(struct ldb_module *module, struct ldb_request *req) +{ +	struct dsdb_control_current_partition *partition; +	struct partition_private_data *data; +	struct ldb_dn *schema_dn; +	struct partition_context *ac; +	struct ldb_module *backend; +	int ret; + +	schema_dn = talloc_get_type(req->op.extended.data, struct ldb_dn); +	if (!schema_dn) { +		ldb_debug(module->ldb, LDB_DEBUG_FATAL, "partition_extended: invalid extended data\n"); +		return LDB_ERR_PROTOCOL_ERROR; +	} + +	data = talloc_get_type(module->private_data, struct partition_private_data); +	if (!data) { +		return LDB_ERR_OPERATIONS_ERROR; +	} +	 +	partition = find_partition( data, schema_dn ); +	if (!partition) { +		return ldb_next_request(module, req); +	} + +	ac = partition_init_handle(req, module); +	if (!ac) { +		return LDB_ERR_OPERATIONS_ERROR; +	} + +	backend = make_module_for_next_request(req, module->ldb, partition->module); +	if (!backend) { +		return LDB_ERR_OPERATIONS_ERROR; +	} + +	ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition); +	if (ret != LDB_SUCCESS) { +		return ret; +	} + +	return ldb_next_request(backend, req); +} + +  /* extended */  static int partition_extended(struct ldb_module *module, struct ldb_request *req)  { @@ -708,6 +752,11 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req  		return partition_extended_replicated_objects(module, req);  	} +	/* forward schemaUpdateNow operation to schema_fsmo module*/ +	if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) == 0) { +		return partition_extended_schema_update_now( module, req ); +	}	 +  	/*   	 * as the extended operation has no dn  	 * we need to send it to all partitions diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 3e442b6341..413ec12479 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -140,6 +140,11 @@ struct setup_password_fields_io {  		struct samr_Password *nt_history;  		uint32_t lm_history_len;  		struct samr_Password *lm_history; +		const char *salt; +		DATA_BLOB aes_256; +		DATA_BLOB aes_128; +		DATA_BLOB des_md5; +		DATA_BLOB des_crc;  		struct ldb_val supplemental;  		NTTIME last_set;  		uint32_t kvno; @@ -216,21 +221,12 @@ static int setup_lm_fields(struct setup_password_fields_io *io)  	return LDB_SUCCESS;  } -static int setup_primary_kerberos(struct setup_password_fields_io *io, -				  const struct supplementalCredentialsBlob *old_scb, -				  struct package_PrimaryKerberosBlob *pkb) +static int setup_kerberos_keys(struct setup_password_fields_io *io)  {  	krb5_error_code krb5_ret;  	Principal *salt_principal;  	krb5_salt salt;  	krb5_keyblock key; -	uint32_t k=0; -	struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3; -	struct supplementalCredentialsPackage *old_scp = NULL; -	struct package_PrimaryKerberosBlob _old_pkb; -	struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL; -	uint32_t i; -	enum ndr_err_code ndr_err;  	/* Many, many thanks to lukeh@padl.com for this  	 * algorithm, described in his Nov 10 2004 mail to @@ -290,7 +286,7 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  	}  	if (krb5_ret) {  		ldb_asprintf_errstring(io->ac->module->ldb, -				       "setup_primary_kerberos: " +				       "setup_kerberos_keys: "  				       "generation of a salting principal failed: %s",  				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR; @@ -304,81 +300,72 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  	krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);  	if (krb5_ret) {  		ldb_asprintf_errstring(io->ac->module->ldb, -				       "setup_primary_kerberos: " +				       "setup_kerberos_keys: "  				       "generation of krb5_salt failed: %s",  				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR;  	}  	/* create a talloc copy */ -	pkb3->salt.string = talloc_strndup(io->ac, -					  salt.saltvalue.data, -					  salt.saltvalue.length); +	io->g.salt = talloc_strndup(io->ac, +				    salt.saltvalue.data, +				    salt.saltvalue.length);  	krb5_free_salt(io->smb_krb5_context->krb5_context, salt); -	if (!pkb3->salt.string) { +	if (!io->g.salt) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	} -	salt.saltvalue.data	= discard_const(pkb3->salt.string); -	salt.saltvalue.length	= strlen(pkb3->salt.string); +	salt.saltvalue.data	= discard_const(io->g.salt); +	salt.saltvalue.length	= strlen(io->g.salt);  	/* -	 * prepare generation of keys -	 * -	 * ENCTYPE_AES256_CTS_HMAC_SHA1_96 (disabled by default) -	 * ENCTYPE_DES_CBC_MD5 -	 * ENCTYPE_DES_CBC_CRC -	 * -	 * NOTE: update num_keys when you add another enctype! +	 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of +	 * the salt and the cleartext password  	 */ -	pkb3->num_keys	= 3; -	pkb3->keys	= talloc_array(io->ac, struct package_PrimaryKerberosKey, pkb3->num_keys); -	if (!pkb3->keys) { -		ldb_oom(io->ac->module->ldb); +	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context, +					   ENCTYPE_AES256_CTS_HMAC_SHA1_96, +					   io->n.cleartext, +					   salt, +					   &key); +	if (krb5_ret) { +		ldb_asprintf_errstring(io->ac->module->ldb, +				       "setup_kerberos_keys: " +				       "generation of a aes256-cts-hmac-sha1-96 key failed: %s", +				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR;  	} -	pkb3->unknown3	= talloc_zero_array(io->ac, uint64_t, pkb3->num_keys); -	if (!pkb3->unknown3) { +	io->g.aes_256 = data_blob_talloc(io->ac, +					 key.keyvalue.data, +					 key.keyvalue.length); +	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); +	if (!io->g.aes_256.data) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	} -	if (lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"), NULL, "password_hash", "create_aes_key", false)) { -	/* -	 * TODO: -	 * -	 * w2k and w2k3 doesn't support AES, so we'll not include -	 * the AES key here yet. -	 * -	 * Also we don't have an example supplementalCredentials blob -	 * from Windows Longhorn Server with AES support -	 * -	 */  	/* -	 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of +	 * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of  	 * the salt and the cleartext password  	 */  	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context, -					   ENCTYPE_AES256_CTS_HMAC_SHA1_96, +					   ENCTYPE_AES128_CTS_HMAC_SHA1_96,  					   io->n.cleartext,  					   salt,  					   &key); -	pkb3->keys[k].keytype	= ENCTYPE_AES256_CTS_HMAC_SHA1_96; -	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB); -	if (!pkb3->keys[k].value) { -		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -		ldb_oom(io->ac->module->ldb); +	if (krb5_ret) { +		ldb_asprintf_errstring(io->ac->module->ldb, +				       "setup_kerberos_keys: " +				       "generation of a aes128-cts-hmac-sha1-96 key failed: %s", +				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR;  	} -	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value, -						   key.keyvalue.data, -						   key.keyvalue.length); +	io->g.aes_128 = data_blob_talloc(io->ac, +					 key.keyvalue.data, +					 key.keyvalue.length);  	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -	if (!pkb3->keys[k].value->data) { +	if (!io->g.aes_128.data) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	} -	k++; -}  	/*  	 * create ENCTYPE_DES_CBC_MD5 key out of @@ -389,22 +376,21 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  					   io->n.cleartext,  					   salt,  					   &key); -	pkb3->keys[k].keytype	= ENCTYPE_DES_CBC_MD5; -	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB); -	if (!pkb3->keys[k].value) { -		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -		ldb_oom(io->ac->module->ldb); +	if (krb5_ret) { +		ldb_asprintf_errstring(io->ac->module->ldb, +				       "setup_kerberos_keys: " +				       "generation of a des-cbc-md5 key failed: %s", +				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR;  	} -	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value, -						   key.keyvalue.data, -						   key.keyvalue.length); +	io->g.des_md5 = data_blob_talloc(io->ac, +					 key.keyvalue.data, +					 key.keyvalue.length);  	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -	if (!pkb3->keys[k].value->data) { +	if (!io->g.des_md5.data) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	} -	k++;  	/*  	 * create ENCTYPE_DES_CBC_CRC key out of @@ -415,30 +401,60 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  					   io->n.cleartext,  					   salt,  					   &key); -	pkb3->keys[k].keytype	= ENCTYPE_DES_CBC_CRC; -	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB); -	if (!pkb3->keys[k].value) { -		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -		ldb_oom(io->ac->module->ldb); +	if (krb5_ret) { +		ldb_asprintf_errstring(io->ac->module->ldb, +				       "setup_kerberos_keys: " +				       "generation of a des-cbc-crc key failed: %s", +				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));  		return LDB_ERR_OPERATIONS_ERROR;  	} -	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value, -						   key.keyvalue.data, -						   key.keyvalue.length); +	io->g.des_crc = data_blob_talloc(io->ac, +					 key.keyvalue.data, +					 key.keyvalue.length);  	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); -	if (!pkb3->keys[k].value->data) { +	if (!io->g.des_crc.data) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	} -	k++; -	/* fix up key number */ -	pkb3->num_keys = k; +	return LDB_SUCCESS; +} + +static int setup_primary_kerberos(struct setup_password_fields_io *io, +				  const struct supplementalCredentialsBlob *old_scb, +				  struct package_PrimaryKerberosBlob *pkb) +{ +	struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3; +	struct supplementalCredentialsPackage *old_scp = NULL; +	struct package_PrimaryKerberosBlob _old_pkb; +	struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL; +	uint32_t i; +	enum ndr_err_code ndr_err; + +	/* +	 * prepare generation of keys +	 * +	 * ENCTYPE_DES_CBC_MD5 +	 * ENCTYPE_DES_CBC_CRC +	 */ +	pkb3->salt.string	= io->g.salt; +	pkb3->num_keys		= 2; +	pkb3->keys		= talloc_array(io->ac, +					       struct package_PrimaryKerberosKey, +					       pkb3->num_keys); +	if (!pkb3->keys) { +		ldb_oom(io->ac->module->ldb); +		return LDB_ERR_OPERATIONS_ERROR; +	} + +	pkb3->keys[0].keytype	= ENCTYPE_DES_CBC_MD5; +	pkb3->keys[0].value	= &io->g.des_md5; +	pkb3->keys[1].keytype	= ENCTYPE_DES_CBC_CRC; +	pkb3->keys[1].value	= &io->g.des_crc;  	/* initialize the old keys to zero */  	pkb3->num_old_keys	= 0;  	pkb3->old_keys		= NULL; -	pkb3->unknown3_old	= NULL;  	/* if there're no old keys, then we're done */  	if (!old_scb) { @@ -446,10 +462,6 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  	}  	for (i=0; i < old_scb->sub.num_packages; i++) { -		if (old_scb->sub.packages[i].unknown1 != 0x00000001) { -			continue; -		} -  		if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {  			continue;  		} @@ -503,7 +515,117 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,  	/* fill in the old keys */  	pkb3->num_old_keys	= old_pkb3->num_keys;  	pkb3->old_keys		= old_pkb3->keys; -	pkb3->unknown3_old	= old_pkb3->unknown3; + +	return LDB_SUCCESS; +} + +static int setup_primary_kerberos_newer(struct setup_password_fields_io *io, +					const struct supplementalCredentialsBlob *old_scb, +					struct package_PrimaryKerberosNewerBlob *pkb) +{ +	struct package_PrimaryKerberosNewerCtr4 *pkb4 = &pkb->ctr.ctr4; +	struct supplementalCredentialsPackage *old_scp = NULL; +	struct package_PrimaryKerberosNewerBlob _old_pkb; +	struct package_PrimaryKerberosNewerCtr4 *old_pkb4 = NULL; +	uint32_t i; +	enum ndr_err_code ndr_err; + +	/* +	 * prepare generation of keys +	 * +	 * ENCTYPE_AES256_CTS_HMAC_SHA1_96 +	 * ENCTYPE_AES128_CTS_HMAC_SHA1_96 +	 * ENCTYPE_DES_CBC_MD5 +	 * ENCTYPE_DES_CBC_CRC +	 */ +	pkb4->salt.string	= io->g.salt; +	pkb4->num_keys		= 4; +	pkb4->keys		= talloc_array(io->ac, +					       struct package_PrimaryKerberosNewerKey, +					       pkb4->num_keys); +	if (!pkb4->keys) { +		ldb_oom(io->ac->module->ldb); +		return LDB_ERR_OPERATIONS_ERROR; +	} + +	pkb4->keys[0].keytype	= ENCTYPE_AES256_CTS_HMAC_SHA1_96; +	pkb4->keys[0].value	= &io->g.aes_256; +	pkb4->keys[1].keytype	= ENCTYPE_AES128_CTS_HMAC_SHA1_96; +	pkb4->keys[1].value	= &io->g.aes_128; +	pkb4->keys[2].keytype	= ENCTYPE_DES_CBC_MD5; +	pkb4->keys[2].value	= &io->g.des_md5; +	pkb4->keys[3].keytype	= ENCTYPE_DES_CBC_CRC; +	pkb4->keys[3].value	= &io->g.des_crc; + +	/* initialize the old keys to zero */ +	pkb4->num_old_keys1	= 0; +	pkb4->old_keys1		= NULL; +	pkb4->num_old_keys2	= 0; +	pkb4->old_keys2		= NULL; + +	/* if there're no old keys, then we're done */ +	if (!old_scb) { +		return LDB_SUCCESS; +	} + +	for (i=0; i < old_scb->sub.num_packages; i++) { +		if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) { +			continue; +		} + +		if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) { +			continue; +		} + +		old_scp = &old_scb->sub.packages[i]; +		break; +	} +	/* Primary:Kerberos element of supplementalCredentials */ +	if (old_scp) { +		DATA_BLOB blob; + +		blob = strhex_to_data_blob(old_scp->data); +		if (!blob.data) { +			ldb_oom(io->ac->module->ldb); +			return LDB_ERR_OPERATIONS_ERROR; +		} +		talloc_steal(io->ac, blob.data); + +		/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */ +		ndr_err = ndr_pull_struct_blob(&blob, io->ac, +					       lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), +					       &_old_pkb, +					       (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosNewerBlob); +		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +			NTSTATUS status = ndr_map_error2ntstatus(ndr_err); +			ldb_asprintf_errstring(io->ac->module->ldb, +					       "setup_primary_kerberos_newer: " +					       "failed to pull old package_PrimaryKerberosNewerBlob: %s", +					       nt_errstr(status)); +			return LDB_ERR_OPERATIONS_ERROR; +		} + +		if (_old_pkb.version != 4) { +			ldb_asprintf_errstring(io->ac->module->ldb, +					       "setup_primary_kerberos: " +					       "package_PrimaryKerberosNewerBlob version[%u] expected[4]", +					       _old_pkb.version); +			return LDB_ERR_OPERATIONS_ERROR; +		} + +		old_pkb4 = &_old_pkb.ctr.ctr4; +	} + +	/* if we didn't found the old keys we're done */ +	if (!old_pkb4) { +		return LDB_SUCCESS; +	} + +	/* fill in the old keys */ +	pkb4->num_old_keys1	= old_pkb4->num_keys; +	pkb4->old_keys1		= old_pkb4->keys; +	pkb4->num_old_keys2	= old_pkb4->num_old_keys1; +	pkb4->old_keys2		= old_pkb4->old_keys1;  	return LDB_SUCCESS;  } @@ -845,30 +967,48 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  	struct supplementalCredentialsBlob scb;  	struct supplementalCredentialsBlob _old_scb;  	struct supplementalCredentialsBlob *old_scb = NULL; -	/* Packages + (Kerberos, WDigest and maybe CLEARTEXT) */ -	uint32_t num_packages = 1 + 2; -	struct supplementalCredentialsPackage packages[1+3]; -	struct supplementalCredentialsPackage *pp = &packages[0]; -	struct supplementalCredentialsPackage *pk = &packages[1]; -	struct supplementalCredentialsPackage *pd = &packages[2]; -	struct supplementalCredentialsPackage *pc = NULL; +	/* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */ +	uint32_t num_names = 0; +	const char *names[1+4]; +	uint32_t num_packages = 0; +	struct supplementalCredentialsPackage packages[1+4]; +	/* Packages */ +	struct supplementalCredentialsPackage *pp = NULL;  	struct package_PackagesBlob pb;  	DATA_BLOB pb_blob;  	char *pb_hexstr; +	/* Primary:Kerberos-Newer-Keys */ +	const char **nkn = NULL; +	struct supplementalCredentialsPackage *pkn = NULL; +	struct package_PrimaryKerberosNewerBlob pknb; +	DATA_BLOB pknb_blob; +	char *pknb_hexstr; +	/* Primary:Kerberos */ +	const char **nk = NULL; +	struct supplementalCredentialsPackage *pk = NULL;  	struct package_PrimaryKerberosBlob pkb;  	DATA_BLOB pkb_blob;  	char *pkb_hexstr; +	/* Primary:WDigest */ +	const char **nd = NULL; +	struct supplementalCredentialsPackage *pd = NULL;  	struct package_PrimaryWDigestBlob pdb;  	DATA_BLOB pdb_blob;  	char *pdb_hexstr; +	/* Primary:CLEARTEXT */ +	const char **nc = NULL; +	struct supplementalCredentialsPackage *pc = NULL;  	struct package_PrimaryCLEARTEXTBlob pcb;  	DATA_BLOB pcb_blob;  	char *pcb_hexstr;  	int ret;  	enum ndr_err_code ndr_err;  	uint8_t zero16[16]; +	bool do_newer_keys = false; +	bool do_cleartext = false;  	ZERO_STRUCT(zero16); +	ZERO_STRUCT(names);  	if (!io->n.cleartext) {  		/*  @@ -880,7 +1020,9 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  	/* if there's an old supplementaCredentials blob then parse it */  	if (io->o.supplemental) { -		ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_scb, +		ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac, +						   lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), +						   &_old_scb,  						   (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);  		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {  			NTSTATUS status = ndr_map_error2ntstatus(ndr_err); @@ -891,22 +1033,101 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  			return LDB_ERR_OPERATIONS_ERROR;  		} -		old_scb = &_old_scb; +		if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) { +			old_scb = &_old_scb; +		} else { +			ldb_debug(io->ac->module->ldb, LDB_DEBUG_ERROR, +					       "setup_supplemental_field: " +					       "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]", +					       _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE); +		}  	} +	/* TODO: do the correct check for this, it maybe depends on the functional level? */ +	do_newer_keys = lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"), +				     NULL, "password_hash", "create_aes_key", false); +  	if (io->domain->store_cleartext &&  	    (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) { -		pc = &packages[3]; -		num_packages++; +		do_cleartext = true; +	} + +	/* +	 * The ordering is this +	 * +	 * Primary:Kerberos-Newer-Keys (optional) +	 * Primary:Kerberos +	 * Primary:WDigest +	 * Primary:CLEARTEXT (optional) +	 * +	 * And the 'Packages' package is insert before the last +	 * other package. +	 */ +	if (do_newer_keys) { +		/* Primary:Kerberos-Newer-Keys */ +		nkn = &names[num_names++]; +		pkn = &packages[num_packages++]; +	} + +	/* Primary:Kerberos */ +	nk = &names[num_names++]; +	pk = &packages[num_packages++]; + +	if (!do_cleartext) { +		/* Packages */ +		pp = &packages[num_packages++]; +	} + +	/* Primary:WDigest */ +	nd = &names[num_names++]; +	pd = &packages[num_packages++]; + +	if (do_cleartext) { +		/* Packages */ +		pp = &packages[num_packages++]; + +		/* Primary:CLEARTEXT */ +		nc = &names[num_names++]; +		pc = &packages[num_packages++];  	} -	/* Kerberos, WDigest, CLEARTEXT and termination(counted by the Packages element) */ -	pb.names = talloc_zero_array(io->ac, const char *, num_packages); +	if (pkn) { +		/* +		 * setup 'Primary:Kerberos-Newer-Keys' element +		 */ +		*nkn = "Kerberos-Newer-Keys"; + +		ret = setup_primary_kerberos_newer(io, old_scb, &pknb); +		if (ret != LDB_SUCCESS) { +			return ret; +		} + +		ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac, +					       lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), +					       &pknb, +					       (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosNewerBlob); +		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +			NTSTATUS status = ndr_map_error2ntstatus(ndr_err); +			ldb_asprintf_errstring(io->ac->module->ldb, +					       "setup_supplemental_field: " +					       "failed to push package_PrimaryKerberosNeverBlob: %s", +					       nt_errstr(status)); +			return LDB_ERR_OPERATIONS_ERROR; +		} +		pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob); +		if (!pknb_hexstr) { +			ldb_oom(io->ac->module->ldb); +			return LDB_ERR_OPERATIONS_ERROR; +		} +		pkn->name	= "Primary:Kerberos-Newer-Keys"; +		pkn->reserved	= 1; +		pkn->data	= pknb_hexstr; +	}  	/*  	 * setup 'Primary:Kerberos' element  	 */ -	pb.names[0] = "Kerberos"; +	*nk = "Kerberos";  	ret = setup_primary_kerberos(io, old_scb, &pkb);  	if (ret != LDB_SUCCESS) { @@ -925,29 +1146,19 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  				       nt_errstr(status));  		return LDB_ERR_OPERATIONS_ERROR;  	} -	/* -	 * TODO: -	 * -	 * This is ugly, but we want to generate the same blob as -	 * w2k and w2k3...we should handle this in the idl -	 */ -	if (!data_blob_append(io->ac, &pkb_blob, zero16, sizeof(zero16))) { -		ldb_oom(io->ac->module->ldb); -		return LDB_ERR_OPERATIONS_ERROR; -	}  	pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);  	if (!pkb_hexstr) {  		ldb_oom(io->ac->module->ldb);  		return LDB_ERR_OPERATIONS_ERROR;  	}  	pk->name	= "Primary:Kerberos"; -	pk->unknown1	= 1; +	pk->reserved	= 1;  	pk->data	= pkb_hexstr;  	/*  	 * setup 'Primary:WDigest' element  	 */ -	pb.names[1] = "WDigest"; +	*nd = "WDigest";  	ret = setup_primary_wdigest(io, old_scb, &pdb);  	if (ret != LDB_SUCCESS) { @@ -972,14 +1183,14 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  		return LDB_ERR_OPERATIONS_ERROR;  	}  	pd->name	= "Primary:WDigest"; -	pd->unknown1	= 1; +	pd->reserved	= 1;  	pd->data	= pdb_hexstr;  	/*  	 * setup 'Primary:CLEARTEXT' element  	 */  	if (pc) { -		pb.names[2]	= "CLEARTEXT"; +		*nc		= "CLEARTEXT";  		pcb.cleartext	= io->n.cleartext; @@ -1001,13 +1212,14 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  			return LDB_ERR_OPERATIONS_ERROR;  		}  		pc->name	= "Primary:CLEARTEXT"; -		pc->unknown1	= 1; +		pc->reserved	= 1;  		pc->data	= pcb_hexstr;  	}  	/*  	 * setup 'Packages' element  	 */ +	pb.names = names;  	ndr_err = ndr_push_struct_blob(&pb_blob, io->ac,   				       lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),   				       &pb, @@ -1026,12 +1238,13 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)  		return LDB_ERR_OPERATIONS_ERROR;  	}  	pp->name	= "Packages"; -	pp->unknown1	= 2; +	pp->reserved	= 2;  	pp->data	= pb_hexstr;  	/*  	 * setup 'supplementalCredentials' value  	 */ +	ZERO_STRUCT(scb);  	scb.sub.num_packages	= num_packages;  	scb.sub.packages	= packages; @@ -1083,7 +1296,7 @@ static int setup_password_fields(struct setup_password_fields_io *io)  		return LDB_ERR_UNWILLING_TO_PERFORM;  	} -	if (io->n.cleartext && !io->n.nt_hash) { +	if (io->n.cleartext) {  		struct samr_Password *hash;  		hash = talloc(io->ac, struct samr_Password); @@ -1104,7 +1317,7 @@ static int setup_password_fields(struct setup_password_fields_io *io)  		}  	} -	if (io->n.cleartext && !io->n.lm_hash) { +	if (io->n.cleartext) {  		struct samr_Password *hash;  		hash = talloc(io->ac, struct samr_Password); @@ -1122,6 +1335,13 @@ static int setup_password_fields(struct setup_password_fields_io *io)  		}  	} +	if (io->n.cleartext) { +		ret = setup_kerberos_keys(io); +		if (ret != 0) { +			return ret; +		} +	} +  	ret = setup_nt_fields(io);  	if (ret != 0) {  		return ret; diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index 75f99a139d..97491a2ae3 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -391,9 +391,50 @@ static int rootdse_init(struct ldb_module *module)  	return ldb_next_init(module);  } +static int rootdse_modify(struct ldb_module *module, struct ldb_request *req) +{ +	struct ldb_result *ext_res; +	int ret; +	struct ldb_dn *schema_dn; +	struct ldb_message_element *schemaUpdateNowAttr; +	 +	/* +		If dn is not "" we should let it pass through +	*/ +	if (!ldb_dn_is_null(req->op.mod.message->dn)) { +		return ldb_next_request(module, req); +	} +	 +	/* +		dn is empty so check for schemaUpdateNow attribute +		"The type of modification and values specified in the LDAP modify operation do not matter." MSDN +	*/ +	schemaUpdateNowAttr = ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow"); +	if (!schemaUpdateNowAttr) { +		return LDB_ERR_OPERATIONS_ERROR; +	} + +	schema_dn = samdb_schema_dn(module->ldb); +	if (!schema_dn) { +		ldb_reset_err_string(module->ldb); +		ldb_debug(module->ldb, LDB_DEBUG_WARNING, +			  "rootdse_modify: no schema dn present: (skip ldb_extended call)\n"); +		return ldb_next_request(module, req); +	} + +	ret = ldb_extended(module->ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res); +	if (ret != LDB_SUCCESS) { +		return LDB_ERR_OPERATIONS_ERROR; +	} +	 +	talloc_free(ext_res); +	return ret; +} +  _PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = {  	.name			= "rootdse", -	.init_context           = rootdse_init, -	.search                 = rootdse_search, -	.request		= rootdse_request +	.init_context   = rootdse_init, +	.search         = rootdse_search, +	.request		= rootdse_request, +	.modify         = rootdse_modify  }; diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c index a397228723..2acc5c0af4 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c @@ -148,8 +148,70 @@ static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)  	return ldb_next_request(module, req);  } +static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req) +{ +	WERROR status; +	struct ldb_dn *schema_dn; +	struct dsdb_schema *schema; +	char *error_string = NULL; +	int ret; +	TALLOC_CTX *mem_ctx; +	 +	if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) { +		return ldb_next_request(module, req); +	} +	 +	schema_dn = samdb_schema_dn(module->ldb); +	if (!schema_dn) { +		ldb_reset_err_string(module->ldb); +		ldb_debug(module->ldb, LDB_DEBUG_WARNING, +			  "schema_fsmo_extended: no schema dn present: (skip schema loading)\n"); +		return ldb_next_request(module, req); +	} +	 +	mem_ctx = talloc_new(module); +	if (!mem_ctx) { +		ldb_oom(module->ldb); +		return LDB_ERR_OPERATIONS_ERROR; +	} +	 +	ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb, +					 lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")), +					 schema_dn, &schema, &error_string); + +	if (ret == LDB_ERR_NO_SUCH_OBJECT) { +		ldb_reset_err_string(module->ldb); +		ldb_debug(module->ldb, LDB_DEBUG_WARNING, +			  "schema_fsmo_extended: no schema head present: (skip schema loading)\n"); +		talloc_free(mem_ctx); +		return ldb_next_request(module, req); +	} + +	if (ret != LDB_SUCCESS) { +		ldb_asprintf_errstring(module->ldb,  +				       "schema_fsmo_extended: dsdb_schema load failed: %s", +				       error_string); +		talloc_free(mem_ctx); +		return ldb_next_request(module, req); +	} + +	/* Replace the old schema*/ +	ret = dsdb_set_schema(module->ldb, schema); +	if (ret != LDB_SUCCESS) { +		ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, +			      "schema_fsmo_extended: dsdb_set_schema() failed: %d:%s", +			      ret, ldb_strerror(ret)); +		talloc_free(mem_ctx); +		return ret; +	} + +	talloc_free(mem_ctx); +	return LDB_SUCCESS; +} +  _PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {  	.name		= "schema_fsmo",  	.init_context	= schema_fsmo_init, -	.add		= schema_fsmo_add +	.add		= schema_fsmo_add, +	.extended	= schema_fsmo_extended  }; diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 75aa819ccd..b8a3e16d46 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -90,4 +90,6 @@ struct dsdb_pdc_fsmo {  	struct ldb_dn *master_dn;  }; +#define DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID "1.3.6.1.4.1.7165.4.4.2" +  #endif /* __SAMDB_H__ */ diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 71d952b944..2ec5ad34b1 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -268,18 +268,145 @@ WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const  WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)  { +	return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out); +} + + +WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out) +{  	uint32_t i;  	for (i=0; i < schema->num_prefixes; i++) { +		const char *val; +		if (schema->prefixes[i].id != (in & 0xFFFF0000)) { +			continue; +		} + +		val = talloc_asprintf(mem_ctx, "%s%u", +				      schema->prefixes[i].oid, +				      in & 0xFFFF); +		W_ERROR_HAVE_NO_MEMORY(val); + +		*out = val; +		return WERR_OK; +	} + +	return WERR_DS_NO_MSDS_INTID; +} + +/* + * this function is called from within a ldb transaction from the schema_fsmo module + */ +WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid) +{ +	WERROR status; +	uint32_t num_prefixes; +	struct dsdb_schema_oid_prefix *prefixes; +	struct ldb_val ndr_blob; +	TALLOC_CTX *mem_ctx; +	uint32_t out; + +	mem_ctx = talloc_new(ldb); +	W_ERROR_HAVE_NO_MEMORY(mem_ctx); + +	/* Read prefixes from disk*/ +	status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes );  +	if (!W_ERROR_IS_OK(status)) { +		DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb failed\n")); +		talloc_free(mem_ctx); +		return status; +	} + +	/* Check if there is a prefix for the oid in the prefixes array*/ +	status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out );  +	if (W_ERROR_IS_OK(status)) { +		/* prefix found*/ +		talloc_free(mem_ctx); +		return status; +	} +	/* Update prefix map in ldb*/ +	/* Update the prefixes */ +	status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid); +	if (!W_ERROR_IS_OK(status)) { +		DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update failed\n")); +		talloc_free(mem_ctx); +		return status; +	} +	/* Convert prefixes in ndr blob*/ +	status = dsdb_write_prefixes_to_ndr( mem_ctx, ldb, num_prefixes, prefixes, &ndr_blob ); +	if (!W_ERROR_IS_OK(status)) { +		DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ndr failed\n")); +		talloc_free(mem_ctx); +		return status; +	} + +	/* Update prefixMap in ldb*/ +	status = dsdb_write_prefixes_to_ldb( mem_ctx, ldb, &ndr_blob ); +	if (!W_ERROR_IS_OK(status)) { +		DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb failed\n")); +		talloc_free(mem_ctx); +		return status; +	} + +	talloc_free(mem_ctx); +	return status; +} + +WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid) +{ +	uint32_t new_num_prefixes, index_new_prefix, new_entry_id; +	const char* lastDotOffset; +	size_t size; +	 +	new_num_prefixes = *num_prefixes + 1; +	index_new_prefix = *num_prefixes; +	new_entry_id = (*num_prefixes)<<16; + +	/* Extract the prefix from the oid*/ +	lastDotOffset = strrchr(oid, '.'); +	if (lastDotOffset == NULL) { +		DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n")); +		return WERR_NOT_FOUND; +	} + +	/* Calculate the size of the remainig string that should be the prefix of it */ +	size = strlen(oid) - strlen(lastDotOffset); +	if (size <= 0) { +		DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n")); +		return WERR_FOOBAR; +	} +	/* Add one because we need to copy the dot */ +	size += 1; + +	/* Create a spot in the prefixMap for one more prefix*/ +	(*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes); +	W_ERROR_HAVE_NO_MEMORY(*prefixes); + +	/* Add the new prefix entry*/ +	(*prefixes)[index_new_prefix].id = new_entry_id; +	(*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size); +	(*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid); + +	/* Increase num_prefixes because new prefix has been added */ +	++(*num_prefixes); + +	return WERR_OK; +} + +WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out) +{ +	uint32_t i; + +	for (i=0; i < num_prefixes; i++) {  		const char *val_str;  		char *end_str;  		unsigned val; -		if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) { +		if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) {  			continue;  		} -		val_str = in + schema->prefixes[i].oid_len; +		val_str = in + prefixes[i].oid_len;  		end_str = NULL;  		errno = 0; @@ -305,58 +432,152 @@ WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32  			return WERR_INVALID_PARAM;  		} -		*out = schema->prefixes[i].id | val; +		*out = prefixes[i].id | val;  		return WERR_OK;  	}  	return WERR_DS_NO_MSDS_INTID;  } -WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out) +WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_val *ndr_blob)  { +	struct ldb_message msg; +	struct ldb_dn *schema_dn; +	struct ldb_message_element el; +	int ret; +	 +	schema_dn = samdb_schema_dn(ldb); +	if (!schema_dn) { +		DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));	 +		return WERR_FOOBAR; +	} +  +	el.num_values = 1; +	el.values = ndr_blob; +	el.flags = LDB_FLAG_MOD_REPLACE; +	el.name = talloc_strdup(mem_ctx, "prefixMap"); +  +	msg.dn = ldb_dn_copy(mem_ctx, schema_dn); +	msg.num_elements = 1; +	msg.elements = ⪙ +  +	ret = ldb_modify( ldb, &msg ); +	if (ret != 0) { +		DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));	 +		return WERR_FOOBAR; + 	} +  +	return WERR_OK; +} + +WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes) +{ +	struct prefixMapBlob *blob; +	enum ndr_err_code ndr_err;  	uint32_t i; +	const struct ldb_val *prefix_val; +	struct ldb_dn *schema_dn; +	struct ldb_result *schema_res; +	int ret;     +	static const char *schema_attrs[] = { +		"prefixMap", +		NULL +	}; -	for (i=0; i < schema->num_prefixes; i++) { -		const char *val; -		if (schema->prefixes[i].id != (in & 0xFFFF0000)) { -			continue; -		} +	schema_dn = samdb_schema_dn(ldb); +	if (!schema_dn) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n")); +		return WERR_FOOBAR; +	} -		val = talloc_asprintf(mem_ctx, "%s%u", -				      schema->prefixes[i].oid, -				      in & 0xFFFF); -		W_ERROR_HAVE_NO_MEMORY(val); +	ret = ldb_search(ldb, schema_dn, LDB_SCOPE_BASE,NULL, schema_attrs,&schema_res); +	if (ret == LDB_ERR_NO_SUCH_OBJECT) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n")); +		return WERR_FOOBAR; +	} else if (ret != LDB_SUCCESS) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n")); +		return WERR_FOOBAR; +	} -		*out = val; -		return WERR_OK; +	prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap"); +	if (!prefix_val) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n")); +		return WERR_FOOBAR;  	} -	return WERR_DS_NO_MSDS_INTID; +	blob = talloc(mem_ctx, struct prefixMapBlob); +	W_ERROR_HAVE_NO_MEMORY(blob); + +	ndr_err = ndr_pull_struct_blob(prefix_val, blob,  +					   lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),  +					   blob, +					   (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob); +	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n")); +		talloc_free(blob); +		return WERR_FOOBAR; +	} + +	if (blob->version != PREFIX_MAP_VERSION_DSDB) { +		DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n")); +		talloc_free(blob); +		return WERR_FOOBAR; +	} +	 +	*num_prefixes = blob->ctr.dsdb.num_mappings; +	*prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes); +	if(!(*prefixes)) { +		talloc_free(blob); +		return WERR_NOMEM; +	} +	for (i=0; i < blob->ctr.dsdb.num_mappings; i++) { +		(*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16; +		(*prefixes)[i].oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid); +		(*prefixes)[i].oid = talloc_asprintf_append((*prefixes)[i].oid, ".");  +		(*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid); +	} + +	talloc_free(blob); +	return WERR_OK;  } -/* - * this function is called from within a ldb transaction from the schema_fsmo module - */ -WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid) + +WERROR dsdb_write_prefixes_to_ndr(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, struct ldb_val *out)  { -	/* -	 * TODO: -	 *	- (maybe) read the old prefixMap attribute and parse it -	 * -	 *	- recheck the prefix doesn't exist (because the ldb -	 *	  has maybe a more uptodate value than schem->prefixes -	 * -	 *	- calculate a new mapping for the oid prefix of full_oid -	 *	- store the new prefixMap attribute -	 * -	 *	- (maybe) update schema->prefixes -	 *	or -	 *	- better find a way to indicate a schema reload, -	 *	  so that other processes also notice the schema change -	 */ -	return WERR_NOT_SUPPORTED; +	struct prefixMapBlob *blob; +	enum ndr_err_code ndr_err; +	uint32_t i; + +	blob = talloc_zero(mem_ctx, struct prefixMapBlob); +	W_ERROR_HAVE_NO_MEMORY(blob); + +	blob->version = PREFIX_MAP_VERSION_DSDB; +	blob->ctr.dsdb.num_mappings = num_prefixes; +	blob->ctr.dsdb.mappings = talloc_realloc(blob, +											blob->ctr.dsdb.mappings, +											struct drsuapi_DsReplicaOIDMapping, +											blob->ctr.dsdb.num_mappings); +	if (!blob->ctr.dsdb.mappings) { +		return WERR_NOMEM; +	} + +	for (i=0; i < num_prefixes; i++) { +		blob->ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16; +		blob->ctr.dsdb.mappings[i].oid.oid = talloc_strdup(blob->ctr.dsdb.mappings, prefixes[i].oid); +	} + +	ndr_err = ndr_push_struct_blob(out, ldb, +					   lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), +					   blob, +					   (ndr_push_flags_fn_t)ndr_push_prefixMapBlob); +	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +		return WERR_FOOBAR; +	} +	 +	return WERR_OK;  } +  #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \  	(p)->elem = samdb_result_string(msg, attr, NULL);\  	if (strict && (p)->elem == NULL) { \ diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 70e578ee0d..9960085b1a 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -190,9 +190,12 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context,  	struct samr_Password *hash;  	const struct ldb_val *sc_val;  	struct supplementalCredentialsBlob scb; -	struct supplementalCredentialsPackage *scp = NULL; +	struct supplementalCredentialsPackage *scpk = NULL; +	struct supplementalCredentialsPackage *scpkn = NULL;  	struct package_PrimaryKerberosBlob _pkb;  	struct package_PrimaryKerberosCtr3 *pkb3 = NULL; +	struct package_PrimaryKerberosNewerBlob _pknb; +	struct package_PrimaryKerberosNewerCtr4 *pkb4 = NULL;  	uint32_t i;  	uint32_t allocated_keys = 0; @@ -221,35 +224,75 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context,  			goto out;  		} +		if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) { +			NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb); +			ret = EINVAL; +			goto out; +		} +  		for (i=0; i < scb.sub.num_packages; i++) { -			if (scb.sub.packages[i].unknown1 != 0x00000001) { -				continue; +			if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) { +				scpkn = &scb.sub.packages[i]; +				if (!scpkn->data || !scpkn->data[0]) { +					scpkn = NULL; +					continue; +				} +				break; +			} else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) { +				scpk = &scb.sub.packages[i]; +				if (!scpk->data || !scpk->data[0]) { +					scpk = NULL; +				} +				/* +				 * we don't break here in hope to find +				 * a Kerberos-Newer-Keys package +				 */  			} +		} +	} +	/* Primary:Kerberos-Newer-Keys element of supplementalCredentials */ +	if (scpkn) { +		DATA_BLOB blob; -			if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) != 0) { -				continue; -			} +		blob = strhex_to_data_blob(scpkn->data); +		if (!blob.data) { +			ret = ENOMEM; +			goto out; +		} +		talloc_steal(mem_ctx, blob.data); -			if (!scb.sub.packages[i].data || !scb.sub.packages[i].data[0]) { -				continue; -			} +		/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */ +		ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, iconv_convenience, &_pknb, +					       (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosNewerBlob); +		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +			krb5_set_error_string(context, "LDB_message2entry_keys: could not parse package_PrimaryKerberosNewerBlob"); +			krb5_warnx(context, "LDB_message2entry_keys: could not parse package_PrimaryKerberosNewerBlob"); +			ret = EINVAL; +			goto out; +		} -			scp = &scb.sub.packages[i]; -			break; +		if (_pknb.version != 4) { +			krb5_set_error_string(context, "LDB_message2entry_keys: could not parse PrimaryKerberosNewer not version 4"); +			krb5_warnx(context, "LDB_message2entry_keys: could not parse PrimaryKerberosNewer not version 4"); +			ret = EINVAL; +			goto out;  		} -	} -	/* Primary:Kerberos element of supplementalCredentials */ -	if (scp) { + +		pkb4 = &_pknb.ctr.ctr4; + +		allocated_keys += pkb4->num_keys; +	} else if (scpk) { +		/* Fallback to Primary:Kerberos element of supplementalCredentials */  		DATA_BLOB blob; -		blob = strhex_to_data_blob(scp->data); +		blob = strhex_to_data_blob(scpk->data);  		if (!blob.data) {  			ret = ENOMEM;  			goto out;  		}  		talloc_steal(mem_ctx, blob.data); -		/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */ +		/* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */  		ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, iconv_convenience, &_pkb,  					       (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);  		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -304,7 +347,68 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context,  		entry_ex->entry.keys.len++;  	} -	if (pkb3) { +	if (pkb4) { +		for (i=0; i < pkb4->num_keys; i++) { +			bool use = true; +			Key key; + +			if (!pkb4->keys[i].value) continue; + +			if (userAccountControl & UF_USE_DES_KEY_ONLY) { +				switch (pkb4->keys[i].keytype) { +				case ENCTYPE_DES_CBC_CRC: +				case ENCTYPE_DES_CBC_MD5: +					break; +				default: +					use = false; +					break; +				} +			} + +			if (!use) continue; + +			key.mkvno = 0; +			key.salt = NULL; + +			if (pkb4->salt.string) { +				DATA_BLOB salt; + +				salt = data_blob_string_const(pkb4->salt.string); + +				key.salt = calloc(1, sizeof(*key.salt)); +				if (key.salt == NULL) { +					ret = ENOMEM; +					goto out; +				} + +				key.salt->type = hdb_pw_salt; + +				ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length); +				if (ret) { +					free(key.salt); +					key.salt = NULL; +					goto out; +				} +			} + +			ret = krb5_keyblock_init(context, +						 pkb4->keys[i].keytype, +						 pkb4->keys[i].value->data, +						 pkb4->keys[i].value->length, +						 &key.key); +			if (ret) { +				if (key.salt) { +					free_Salt(key.salt); +					free(key.salt); +					key.salt = NULL; +				} +				goto out; +			} + +			entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; +			entry_ex->entry.keys.len++; +		} +	} else if (pkb3) {  		for (i=0; i < pkb3->num_keys; i++) {  			bool use = true;  			Key key; @@ -325,6 +429,7 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context,  			if (!use) continue;  			key.mkvno = 0; +			key.salt = NULL;  			if (pkb3->salt.string) {  				DATA_BLOB salt; diff --git a/source4/lib/ldb/ldb_map/ldb_map.c b/source4/lib/ldb/ldb_map/ldb_map.c index 9c189feb11..b3f639dc67 100644 --- a/source4/lib/ldb/ldb_map/ldb_map.c +++ b/source4/lib/ldb/ldb_map/ldb_map.c @@ -810,6 +810,7 @@ static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module,  /* Generate a local message with a mapped objectClass. */  static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)  { +	const struct ldb_map_context *data = map_get_context(module);  	struct ldb_message_element *el, *oc;  	struct ldb_val val;  	int i; @@ -844,10 +845,10 @@ static struct ldb_message_element *map_objectclass_generate_local(struct ldb_mod  		el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);  	} -	val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject"); +	val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);  	val.length = strlen((char *)val.data); -	/* Remove last value if it was "extensibleObject" */ +	/* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */  	if (ldb_val_equal_exact(&val, &el->values[i-1])) {  		el->num_values--;  		el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values); diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 0dc514aeaf..042469602c 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -579,7 +579,7 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """          self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))          self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) -        time.sleep(2) +        time.sleep(4)          print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"          res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE) @@ -835,7 +835,7 @@ member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """          ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn)) -        time.sleep(2) +        time.sleep(4)          attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]          print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete" diff --git a/source4/libnet/libnet_become_dc.c b/source4/libnet/libnet_become_dc.c index 3fece1a9ba..1ce067c321 100644 --- a/source4/libnet/libnet_become_dc.c +++ b/source4/libnet/libnet_become_dc.c @@ -1516,13 +1516,30 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,  	drsuapi->s = s;  	if (!drsuapi->binding) { -		if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", "print", false)) { -			binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,print,seal]", s->source_dsa.dns_name); -			if (composite_nomem(binding_str, c)) return; -		} else { -			binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name); -			if (composite_nomem(binding_str, c)) return; +		char *krb5_str = ""; +		char *print_str = ""; +		/* +		 * Note: Replication only works with Windows 2000 when 'krb5' is +		 *       passed as auth_type here. If NTLMSSP is used, Windows +		 *       2000 returns garbage in the DsGetNCChanges() response +		 *       if encrypted password attributes would be in the response. +		 *       That means the replication of the schema and configuration +		 *       partition works fine, but it fails for the domain partition. +		 */ +		if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", +				 "force krb5", true)) +		{ +			krb5_str = "krb5,"; +		} +		if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", +				 "print", false)) +		{ +			print_str = "print,";  		} +		binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[%s%sseal]", +					      s->source_dsa.dns_name, +					      krb5_str, print_str); +		if (composite_nomem(binding_str, c)) return;  		c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);  		talloc_free(binding_str);  		if (!composite_is_ok(c)) return; @@ -1602,12 +1619,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,  	bind_info28->supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;  #endif  	bind_info28->site_guid			= s->dest_dsa.site_guid; -	if (s->domain.behavior_version == 2) { -		/* TODO: find out how this is really triggered! */ -		bind_info28->u1				= 528; -	} else { -		bind_info28->u1				= 516; -	} +	bind_info28->pid			= 0;  	bind_info28->repl_epoch			= 0;  	drsuapi->bind_info_ctr.length		= 28; @@ -1636,10 +1648,19 @@ static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,  			info24 = &drsuapi->bind_r.out.bind_info->info.info24;  			drsuapi->remote_info28.supported_extensions	= info24->supported_extensions;  			drsuapi->remote_info28.site_guid		= info24->site_guid; -			drsuapi->remote_info28.u1			= info24->u1; +			drsuapi->remote_info28.pid			= info24->pid;  			drsuapi->remote_info28.repl_epoch		= 0;  			break;  		} +		case 48: { +			struct drsuapi_DsBindInfo48 *info48; +			info48 = &drsuapi->bind_r.out.bind_info->info.info48; +			drsuapi->remote_info28.supported_extensions	= info48->supported_extensions; +			drsuapi->remote_info28.site_guid		= info48->site_guid; +			drsuapi->remote_info28.pid			= info48->pid; +			drsuapi->remote_info28.repl_epoch		= info48->repl_epoch; +			break; +		}  		case 28:  			drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;  			break; @@ -2083,7 +2104,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)  		vd[0] = data_blob_talloc(vd, NULL, 4);  		if (composite_nomem(vd[0].data, c)) return; -		SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2003); +		SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2008);  		vs[0].blob		= &vd[0]; diff --git a/source4/libnet/libnet_samsync_ldb.c b/source4/libnet/libnet_samsync_ldb.c index b223a74a31..c72aef7d70 100644 --- a/source4/libnet/libnet_samsync_ldb.c +++ b/source4/libnet/libnet_samsync_ldb.c @@ -198,7 +198,7 @@ static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,  	}  	samdb_msg_add_string(state->sam_ldb, mem_ctx,  -			     msg, "oEMInformation", domain->comment.string); +			     msg, "oEMInformation", domain->oem_information.string);  	samdb_msg_add_int64(state->sam_ldb, mem_ctx,   			    msg, "forceLogoff", domain->force_logoff_time); diff --git a/source4/libnet/libnet_unbecome_dc.c b/source4/libnet/libnet_unbecome_dc.c index cff919018a..6a42fa2370 100644 --- a/source4/libnet/libnet_unbecome_dc.c +++ b/source4/libnet/libnet_unbecome_dc.c @@ -574,7 +574,7 @@ static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s)  	bind_info28				= &s->drsuapi.local_info28;  	bind_info28->supported_extensions	= 0;  	bind_info28->site_guid			= GUID_zero(); -	bind_info28->u1				= 508; +	bind_info28->pid			= 0;  	bind_info28->repl_epoch			= 0;  	s->drsuapi.bind_info_ctr.length		= 28; @@ -612,10 +612,19 @@ static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req)  			info24 = &s->drsuapi.bind_r.out.bind_info->info.info24;  			s->drsuapi.remote_info28.supported_extensions	= info24->supported_extensions;  			s->drsuapi.remote_info28.site_guid		= info24->site_guid; -			s->drsuapi.remote_info28.u1			= info24->u1; +			s->drsuapi.remote_info28.pid			= info24->pid;  			s->drsuapi.remote_info28.repl_epoch		= 0;  			break;  		} +		case 48: { +			struct drsuapi_DsBindInfo48 *info48; +			info48 = &s->drsuapi.bind_r.out.bind_info->info.info48; +			s->drsuapi.remote_info28.supported_extensions	= info48->supported_extensions; +			s->drsuapi.remote_info28.site_guid		= info48->site_guid; +			s->drsuapi.remote_info28.pid			= info48->pid; +			s->drsuapi.remote_info28.repl_epoch		= info48->repl_epoch; +			break; +		}  		case 28:  			s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;  			break; diff --git a/source4/librpc/idl/drsblobs.idl b/source4/librpc/idl/drsblobs.idl index f8cbdac8c5..c876ae7fed 100644 --- a/source4/librpc/idl/drsblobs.idl +++ b/source4/librpc/idl/drsblobs.idl @@ -205,7 +205,7 @@ interface drsblobs {  	typedef struct {  		[value(2*strlen_m(name))] uint16 name_len;  		[value(strlen(data))] uint16 data_len; -		uint16 unknown1; /* 2 for name = 'Packages', 1 for name = 'Primary:*' */ +		uint16 reserved; /* 2 for 'Packages', 1 for 'Primary:*', but should be ignored */  		[charset(UTF16)] uint8 name[name_len];  		/*   		 * the data field contains data as HEX strings @@ -215,6 +215,9 @@ interface drsblobs {  		 *   as non termiated UTF16 strings with  		 *   a UTF16 NULL byte as separator  		 * +		 * 'Primary:Kerberos-Newer-Keys': +		 *    ... +		 *  		 * 'Primary:Kerberos':  		 *    ...  		 * @@ -228,11 +231,16 @@ interface drsblobs {  		[charset(DOS)] uint8 data[data_len];  	} supplementalCredentialsPackage; -	/* this are 0x30 (48) whitespaces (0x20) followed by 'P' (0x50) */ -	const string SUPPLEMENTAL_CREDENTIALS_PREFIX = "                                                P"; +	/* this are 0x30 (48) whitespaces (0x20) */ +	const string SUPPLEMENTAL_CREDENTIALS_PREFIX = "                                                "; + +	typedef [flag(NDR_PAHEX)] enum { +		SUPPLEMENTAL_CREDENTIALS_SIGNATURE = 0x0050 +	} supplementalCredentialsSignature;  	typedef [gensize] struct { -		[value(SUPPLEMENTAL_CREDENTIALS_PREFIX),charset(UTF16)] uint16 prefix[0x31]; +		[value(SUPPLEMENTAL_CREDENTIALS_PREFIX),charset(UTF16)] uint16 prefix[0x30]; +		[value(SUPPLEMENTAL_CREDENTIALS_SIGNATURE)] supplementalCredentialsSignature signature;  		uint16 num_packages;  		supplementalCredentialsPackage packages[num_packages];  	} supplementalCredentialsSubBlob; @@ -264,23 +272,25 @@ interface drsblobs {  	} package_PrimaryKerberosString;  	typedef struct { +		[value(0)] uint16 reserved1; +		[value(0)] uint16 reserved2; +		[value(0)] uint32 reserved3;  		uint32 keytype;  		[value((value?value->length:0))] uint32 value_len;  		[relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value; -		[value(0)] uint32 unknown1; -		[value(0)] uint32 unknown2;  	} package_PrimaryKerberosKey;  	typedef struct {  		uint16 num_keys;  		uint16 num_old_keys;  		package_PrimaryKerberosString salt; -		[value(0)] uint32 unknown1; -		[value(0)] uint32 unknown2;  		package_PrimaryKerberosKey keys[num_keys];  		package_PrimaryKerberosKey old_keys[num_old_keys]; -		udlong unknown3[num_keys]; -		udlong unknown3_old[num_old_keys]; +		[value(0)] uint32 padding1; +		[value(0)] uint32 padding2; +		[value(0)] uint32 padding3; +		[value(0)] uint32 padding4; +		[value(0)] uint32 padding5;  	} package_PrimaryKerberosCtr3;  	typedef [nodiscriminant] union { @@ -296,6 +306,40 @@ interface drsblobs {  		[in] package_PrimaryKerberosBlob blob  		); +	typedef struct { +		[value(0)] uint32 unknown1; +		[value(0)] uint32 unknown2; +		[value(0x00001000)] uint32 unknown3; /* could the the iterator for the AES key creation */ +		uint32 keytype; +		[value((value?value->length:0))] uint32 value_len; +		[relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value; +	} package_PrimaryKerberosNewerKey; + +	typedef struct { +		uint16 num_keys; +		[value(0)] uint16 unknown1; +		uint16 num_old_keys1; +		uint16 num_old_keys2; +		package_PrimaryKerberosString salt; +		[value(0x00001000)] uint32 unknown2; /* could the the iterator for the AES key creation */ +		package_PrimaryKerberosNewerKey keys[num_keys]; +		package_PrimaryKerberosNewerKey old_keys1[num_old_keys1]; +		package_PrimaryKerberosNewerKey old_keys2[num_old_keys2]; +	} package_PrimaryKerberosNewerCtr4; + +	typedef [nodiscriminant] union { +		[case(4)] package_PrimaryKerberosNewerCtr4 ctr4; +	} package_PrimaryKerberosNewerCtr; + +	typedef [public] struct { +		[value(4)] uint32 version; +		[switch_is(version)] package_PrimaryKerberosNewerCtr ctr; +	} package_PrimaryKerberosNewerBlob; + +	void decode_PrimaryKerberosNewer( +		[in] package_PrimaryKerberosNewerBlob blob +		); +  	typedef [public] struct {  		[flag(STR_NOTERM|NDR_REMAINING)] string cleartext;  	} package_PrimaryCLEARTEXTBlob; diff --git a/source4/librpc/idl/drsuapi.idl b/source4/librpc/idl/drsuapi.idl index b9cff5d11d..c19da4fa19 100644 --- a/source4/librpc/idl/drsuapi.idl +++ b/source4/librpc/idl/drsuapi.idl @@ -58,21 +58,36 @@ interface drsuapi  		DRSUAPI_SUPPORTED_EXTENSION_80000000			= 0x80000000  	} drsuapi_SupportedExtensions; +	typedef [bitmap32bit] bitmap { +		DRSUAPI_SUPPORTED_EXTENSION_ADAM			= 0x00000001, +		DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2			= 0x00000002 +	} drsuapi_SupportedExtensionsExt; +  	/* this is used by w2k */  	typedef struct {  		drsuapi_SupportedExtensions supported_extensions;  		GUID site_guid; -		uint32 u1; +		uint32 pid;  	} drsuapi_DsBindInfo24;  	/* this is used by w2k3 */  	typedef struct {  		drsuapi_SupportedExtensions supported_extensions;  		GUID site_guid; -		uint32 u1; +		uint32 pid;  		uint32 repl_epoch;  	} drsuapi_DsBindInfo28; +	/* this is used by w2k8 */ +	typedef struct { +		drsuapi_SupportedExtensions supported_extensions; +		GUID site_guid; +		uint32 pid; +		uint32 repl_epoch; +		drsuapi_SupportedExtensionsExt supported_extensions_ext; +		GUID config_dn_guid; +	} drsuapi_DsBindInfo48; +  	typedef struct {  		[flag(NDR_REMAINING)] DATA_BLOB info;  	} drsuapi_DsBindInfoFallBack; @@ -80,6 +95,7 @@ interface drsuapi  	typedef [nodiscriminant] union {  		[case(24)][subcontext(4)] drsuapi_DsBindInfo24 info24;  		[case(28)][subcontext(4)] drsuapi_DsBindInfo28 info28; +		[case(48)][subcontext(4)] drsuapi_DsBindInfo48 info48;  		[default][subcontext(4)] drsuapi_DsBindInfoFallBack FallBack;  	} drsuapi_DsBindInfo; @@ -1409,7 +1425,7 @@ interface drsuapi  		GUID bind_guid;  		NTTIME_1sec bind_time;  		[flag(NDR_BIG_ENDIAN)] ipv4address client_ip_address; -		uint32 u5; /* this is the same value the client used as u1 in the DsBindInfoX struct */ +		uint32 u5; /* this is the same value the client used as pid in the DsBindInfoX struct */  	} drsuapi_DsReplicaConnection04;  	typedef struct { diff --git a/source4/librpc/idl/netlogon.idl b/source4/librpc/idl/netlogon.idl index 6da496a486..d8f7d2f7e6 100644 --- a/source4/librpc/idl/netlogon.idl +++ b/source4/librpc/idl/netlogon.idl @@ -403,7 +403,7 @@ interface netlogon  	typedef struct {  		lsa_String domain_name; -		lsa_String comment; +		lsa_String oem_information; /* comment */  		dlong force_logoff_time;  		uint16 min_password_length;  		uint16 password_history_length; diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl index 3a11ab752c..b6cce38196 100644 --- a/source4/librpc/idl/samr.idl +++ b/source4/librpc/idl/samr.idl @@ -208,7 +208,7 @@ import "misc.idl", "lsa.idl", "security.idl";  	typedef struct {  		NTTIME force_logoff_time; -		lsa_String comment; +		lsa_String oem_information; /* comment */  		lsa_String domain_name;  		lsa_String primary; /* PDC name if this is a BDC */  		udlong sequence_num; @@ -218,15 +218,15 @@ import "misc.idl", "lsa.idl", "security.idl";  		uint32 num_users;  		uint32 num_groups;  		uint32 num_aliases; -	} samr_DomInfo2; +	} samr_DomGeneralInformation;  	typedef struct {  		NTTIME force_logoff_time;  	} samr_DomInfo3;  	typedef struct { -		lsa_String comment; -	} samr_DomInfo4; +		lsa_String oem_information; /* comment */ +	} samr_DomOEMInformation;  	typedef struct {  		lsa_String domain_name; @@ -250,11 +250,11 @@ import "misc.idl", "lsa.idl", "security.idl";  	} samr_DomInfo9;  	typedef struct { -		samr_DomInfo2 info2; +		samr_DomGeneralInformation general;  		hyper lockout_duration;  		hyper lockout_window;  		uint16 lockout_threshold; -	} samr_DomInfo11; +	} samr_DomGeneralInformation2;  	typedef struct {  		hyper lockout_duration; @@ -271,15 +271,15 @@ import "misc.idl", "lsa.idl", "security.idl";  	typedef [switch_type(uint16)] union {  		[case(1)] samr_DomInfo1 info1; -		[case(2)] samr_DomInfo2 info2; +		[case(2)] samr_DomGeneralInformation general;  		[case(3)] samr_DomInfo3 info3; -		[case(4)] samr_DomInfo4 info4; +		[case(4)] samr_DomOEMInformation oem;  		[case(5)] samr_DomInfo5 info5;  		[case(6)] samr_DomInfo6 info6;  		[case(7)] samr_DomInfo7 info7;  		[case(8)] samr_DomInfo8 info8;  		[case(9)] samr_DomInfo9 info9; -		[case(11)] samr_DomInfo11 info11; +		[case(11)] samr_DomGeneralInformation2 general2;  		[case(12)] samr_DomInfo12 info12;  		[case(13)] samr_DomInfo13 info13;  	} samr_DomainInfo; diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 71c6d5f2cc..32646e85b0 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -647,11 +647,21 @@ NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c,  /*    fetch the user session key - may be default (above) or the SMB session key + +  The key is always truncated to 16 bytes   */  _PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p, -				  DATA_BLOB *session_key) +					   DATA_BLOB *session_key)  { -	return p->conn->security_state.session_key(p->conn, session_key); +	NTSTATUS status; +	status = p->conn->security_state.session_key(p->conn, session_key); +	if (!NT_STATUS_IS_OK(status)) { +		return status; +	} + +	session_key->length = MIN(session_key->length, 16); + +	return NT_STATUS_OK;  } diff --git a/source4/pidl/lib/Parse/Pidl/Expr.pm b/source4/pidl/lib/Parse/Pidl/Expr.pm index 4e02be0575..5524374fae 100644 --- a/source4/pidl/lib/Parse/Pidl/Expr.pm +++ b/source4/pidl/lib/Parse/Pidl/Expr.pm @@ -1127,7 +1127,7 @@ sub new {  	[#Rule 2  		 'exp', 1,  sub -#line 22 "pidl/expr.yp" +#line 22 "./pidl/expr.yp"  { "\"$_[1]\"" }  	],  	[#Rule 3 @@ -1139,199 +1139,199 @@ sub  	[#Rule 5  		 'exp', 2,  sub -#line 25 "pidl/expr.yp" +#line 25 "./pidl/expr.yp"  { "~$_[2]" }  	],  	[#Rule 6  		 'exp', 3,  sub -#line 26 "pidl/expr.yp" +#line 26 "./pidl/expr.yp"  { "$_[1] + $_[3]" }  	],  	[#Rule 7  		 'exp', 3,  sub -#line 27 "pidl/expr.yp" +#line 27 "./pidl/expr.yp"  { "$_[1] - $_[3]" }  	],  	[#Rule 8  		 'exp', 3,  sub -#line 28 "pidl/expr.yp" +#line 28 "./pidl/expr.yp"  { "$_[1] * $_[3]" }  	],  	[#Rule 9  		 'exp', 3,  sub -#line 29 "pidl/expr.yp" +#line 29 "./pidl/expr.yp"  { "$_[1] % $_[3]" }  	],  	[#Rule 10  		 'exp', 3,  sub -#line 30 "pidl/expr.yp" +#line 30 "./pidl/expr.yp"  { "$_[1] < $_[3]" }  	],  	[#Rule 11  		 'exp', 3,  sub -#line 31 "pidl/expr.yp" +#line 31 "./pidl/expr.yp"  { "$_[1] > $_[3]" }  	],  	[#Rule 12  		 'exp', 3,  sub -#line 32 "pidl/expr.yp" +#line 32 "./pidl/expr.yp"  { "$_[1] | $_[3]" }  	],  	[#Rule 13  		 'exp', 3,  sub -#line 33 "pidl/expr.yp" +#line 33 "./pidl/expr.yp"  { "$_[1] == $_[3]" }  	],  	[#Rule 14  		 'exp', 3,  sub -#line 34 "pidl/expr.yp" +#line 34 "./pidl/expr.yp"  { "$_[1] <= $_[3]" }  	],  	[#Rule 15  		 'exp', 3,  sub -#line 35 "pidl/expr.yp" +#line 35 "./pidl/expr.yp"  { "$_[1] => $_[3]" }  	],  	[#Rule 16  		 'exp', 3,  sub -#line 36 "pidl/expr.yp" +#line 36 "./pidl/expr.yp"  { "$_[1] << $_[3]" }  	],  	[#Rule 17  		 'exp', 3,  sub -#line 37 "pidl/expr.yp" +#line 37 "./pidl/expr.yp"  { "$_[1] >> $_[3]" }  	],  	[#Rule 18  		 'exp', 3,  sub -#line 38 "pidl/expr.yp" +#line 38 "./pidl/expr.yp"  { "$_[1] != $_[3]" }  	],  	[#Rule 19  		 'exp', 3,  sub -#line 39 "pidl/expr.yp" +#line 39 "./pidl/expr.yp"  { "$_[1] || $_[3]" }  	],  	[#Rule 20  		 'exp', 3,  sub -#line 40 "pidl/expr.yp" +#line 40 "./pidl/expr.yp"  { "$_[1] && $_[3]" }  	],  	[#Rule 21  		 'exp', 3,  sub -#line 41 "pidl/expr.yp" +#line 41 "./pidl/expr.yp"  { "$_[1] & $_[3]" }  	],  	[#Rule 22  		 'exp', 5,  sub -#line 42 "pidl/expr.yp" +#line 42 "./pidl/expr.yp"  { "$_[1]?$_[3]:$_[5]" }  	],  	[#Rule 23  		 'exp', 2,  sub -#line 43 "pidl/expr.yp" +#line 43 "./pidl/expr.yp"  { "~$_[1]" }  	],  	[#Rule 24  		 'exp', 2,  sub -#line 44 "pidl/expr.yp" +#line 44 "./pidl/expr.yp"  { "not $_[1]" }  	],  	[#Rule 25  		 'exp', 3,  sub -#line 45 "pidl/expr.yp" +#line 45 "./pidl/expr.yp"  { "$_[1] / $_[3]" }  	],  	[#Rule 26  		 'exp', 2,  sub -#line 46 "pidl/expr.yp" +#line 46 "./pidl/expr.yp"  { "-$_[2]" }  	],  	[#Rule 27  		 'exp', 2,  sub -#line 47 "pidl/expr.yp" +#line 47 "./pidl/expr.yp"  { "&$_[2]" }  	],  	[#Rule 28  		 'exp', 3,  sub -#line 48 "pidl/expr.yp" +#line 48 "./pidl/expr.yp"  { "$_[1]^$_[3]" }  	],  	[#Rule 29  		 'exp', 3,  sub -#line 49 "pidl/expr.yp" +#line 49 "./pidl/expr.yp"  { "($_[2])" }  	],  	[#Rule 30  		 'possible_pointer', 1,  sub -#line 53 "pidl/expr.yp" +#line 53 "./pidl/expr.yp"  { $_[0]->_Lookup($_[1]) }  	],  	[#Rule 31  		 'possible_pointer', 2,  sub -#line 54 "pidl/expr.yp" +#line 54 "./pidl/expr.yp"  { $_[0]->_Dereference($_[2]); "*$_[2]" }  	],  	[#Rule 32  		 'var', 1,  sub -#line 57 "pidl/expr.yp" +#line 57 "./pidl/expr.yp"  { $_[0]->_Use($_[1]) }  	],  	[#Rule 33  		 'var', 3,  sub -#line 58 "pidl/expr.yp" +#line 58 "./pidl/expr.yp"  { $_[0]->_Use("$_[1].$_[3]") }  	],  	[#Rule 34  		 'var', 3,  sub -#line 59 "pidl/expr.yp" +#line 59 "./pidl/expr.yp"  { "($_[2])" }  	],  	[#Rule 35  		 'var', 3,  sub -#line 60 "pidl/expr.yp" +#line 60 "./pidl/expr.yp"  { $_[0]->_Use("*$_[1]"); $_[1]."->".$_[3] }  	],  	[#Rule 36  		 'func', 4,  sub -#line 64 "pidl/expr.yp" +#line 64 "./pidl/expr.yp"  { "$_[1]($_[3])" }  	],  	[#Rule 37  		 'opt_args', 0,  sub -#line 65 "pidl/expr.yp" +#line 65 "./pidl/expr.yp"  { "" }  	],  	[#Rule 38 @@ -1349,7 +1349,7 @@ sub  	[#Rule 42  		 'args', 3,  sub -#line 68 "pidl/expr.yp" +#line 68 "./pidl/expr.yp"  { "$_[1], $_[3]" }  	]  ], @@ -1357,7 +1357,7 @@ sub      bless($self,$class);  } -#line 71 "pidl/expr.yp" +#line 71 "./pidl/expr.yp"  package Parse::Pidl::Expr; diff --git a/source4/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm b/source4/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm index 87ed29b54e..d2ab407eb0 100644 --- a/source4/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm +++ b/source4/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm @@ -153,7 +153,6 @@ sub ParseFunction($$$)  	$self->pidl("");  	$self->pidl("status = cli_do_rpc_ndr(cli,");  	$self->pidl("\t\t\tmem_ctx,"); -	$self->pidl("\t\t\tPI_$uif,");  	$self->pidl("\t\t\t&ndr_table_$if,");  	$self->pidl("\t\t\t$ufn,");  	$self->pidl("\t\t\t&r);"); diff --git a/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm index 0d1806a0fa..a0de1f127a 100644 --- a/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm +++ b/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm @@ -770,7 +770,7 @@ sub ParseElementPrint($$$$)  			} else {  				my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; -				$self->pidl("ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", $length);"); +				$self->pidl("ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", (int)$length);");  				$self->pidl("ndr->depth++;");  				$self->pidl("for ($counter=0;$counter<$length;$counter++) {");  				$self->indent; diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index d8dafd61f6..ac36825acd 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -270,11 +270,20 @@ NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,  /*    fetch the user session key - may be default (above) or the SMB session key + +  The key is always truncated to 16 bytes   */  _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,  				  DATA_BLOB *session_key)  { -	return p->auth_state.session_key(p, session_key); +	NTSTATUS status = p->auth_state.session_key(p, session_key); +	if (!NT_STATUS_IS_OK(status)) { +		return status; +	} + +	session_key->length = MIN(session_key->length, 16); + +	return NT_STATUS_OK;  } @@ -534,7 +543,18 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)  	uint32_t context_id;  	const struct dcesrv_interface *iface; -	if (call->pkt.u.bind.assoc_group_id != 0) { +	/* +	 * Association groups allow policy handles to be shared across +	 * multiple client connections.  We don't implement this yet. +	 * +	 * So we just allow 0 if the client wants to create a new +	 * association group. +	 * +	 * And we allow the 0x12345678 value, we give away as +	 * assoc_group_id back to the clients +	 */ +	if (call->pkt.u.bind.assoc_group_id != 0 && +	    call->pkt.u.bind.assoc_group_id != 0x12345678) {  		return dcesrv_bind_nak(call, 0);	  	} diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index e0a222e767..bbb78cb778 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -45,7 +45,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C  	struct ldb_result *ntds_res;  	struct ldb_dn *ntds_dn;  	static const char *ntds_attrs[] = { "ms-DS-ReplicationEpoch", NULL }; -	uint32_t u1; +	uint32_t pid;  	uint32_t repl_epoch;  	int ret; @@ -98,9 +98,12 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C  	repl_epoch = samdb_result_uint(ntds_res->msgs[0], "ms-DS-ReplicationEpoch", 0);  	/* -	 * TODO: find out what this is... +	 * The "process identifier" of the client. +	 * According to the WSPP docs, sectin 5.35, this is +	 * for informational and debugging purposes only. +	 * The assignment is implementation specific.  	 */ -	u1 = 0; +	pid = 0;  	/*  	 * store the clients bind_guid @@ -119,7 +122,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C  			info24 = &r->in.bind_info->info.info24;  			b_state->remote_info28.supported_extensions	= info24->supported_extensions;  			b_state->remote_info28.site_guid		= info24->site_guid; -			b_state->remote_info28.u1			= info24->u1; +			b_state->remote_info28.pid			= info24->pid;  			b_state->remote_info28.repl_epoch		= 0;  			break;  		} @@ -171,8 +174,8 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C  	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;  #endif  	b_state->local_info28.site_guid			= site_guid; -	b_state->local_info28.u1				= u1; -	b_state->local_info28.repl_epoch			= repl_epoch; +	b_state->local_info28.pid			= pid; +	b_state->local_info28.repl_epoch		= repl_epoch;  	/*  	 * allocate the return bind_info diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index eb60f426d8..f02e2325a0 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -1130,9 +1130,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALL  	if (count == -1) {  		return NT_STATUS_INTERNAL_DB_CORRUPTION;  	} -	if (count == 0 || r->in.max_size == 0) { -		return NT_STATUS_OK; -	}  	/* convert to lsa_TrustInformation format */  	entries = talloc_array(mem_ctx, struct lsa_DomainInfo, count); @@ -1218,9 +1215,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca  	if (count == -1) {  		return NT_STATUS_INTERNAL_DB_CORRUPTION;  	} -	if (count == 0 || r->in.max_size == 0) { -		return NT_STATUS_OK; -	}  	/* convert to lsa_DomainInformation format */  	entries = talloc_array(mem_ctx, struct lsa_TrustDomainInfoInfoEx, count); diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 8ee77a6a30..e54d518f76 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -521,10 +521,10 @@ static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,  /*    return DomInfo2  */ -static NTSTATUS dcesrv_samr_info_DomInfo2(struct samr_domain_state *state,  -					  TALLOC_CTX *mem_ctx, -					  struct ldb_message **dom_msgs, -					  struct samr_DomInfo2 *info) +static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,  +						       TALLOC_CTX *mem_ctx, +						       struct ldb_message **dom_msgs, +						       struct samr_DomGeneralInformation *info)  {  	/* This pulls the NetBIOS name from the   	   cn=NTDS Settings,cn=<NETBIOS name of PDC>,.... @@ -538,7 +538,7 @@ static NTSTATUS dcesrv_samr_info_DomInfo2(struct samr_domain_state *state,  	info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",   							    0x8000000000000000LL); -	info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL); +	info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);  	info->domain_name.string  = state->domain_name;  	info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",  @@ -592,12 +592,12 @@ static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,  /*    return DomInfo4  */ -static NTSTATUS dcesrv_samr_info_DomInfo4(struct samr_domain_state *state, +static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,  				   TALLOC_CTX *mem_ctx,  				    struct ldb_message **dom_msgs, -				   struct samr_DomInfo4 *info) +				   struct samr_DomOEMInformation *info)  { -	info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL); +	info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);  	return NT_STATUS_OK;  } @@ -700,13 +700,13 @@ static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,  /*    return DomInfo11  */ -static NTSTATUS dcesrv_samr_info_DomInfo11(struct samr_domain_state *state, +static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,  				    TALLOC_CTX *mem_ctx,  				    struct ldb_message **dom_msgs, -				    struct samr_DomInfo11 *info) +				    struct samr_DomGeneralInformation2 *info)  {  	NTSTATUS status; -	status = dcesrv_samr_info_DomInfo2(state, mem_ctx, dom_msgs, &info->info2); +	status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);  	if (!NT_STATUS_IS_OK(status)) {  		return status;  	} @@ -792,7 +792,7 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,  	case 2:  	{  		static const char * const attrs2[] = {"forceLogoff", -						      "comment",  +						      "oEMInformation",   						      "modifiedCount",   						      "fSMORoleOwner",  						      NULL}; @@ -808,7 +808,7 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,  	}  	case 4:  	{ -		static const char * const attrs2[] = {"comment",  +		static const char * const attrs2[] = {"oEMInformation",   						      NULL};  		attrs = attrs2;  		break; @@ -843,7 +843,7 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,  		break;		  	case 11:  	{ -		static const char * const attrs2[] = { "comment", "forceLogoff",  +		static const char * const attrs2[] = { "oEMInformation", "forceLogoff",   						       "modifiedCount",   						       "lockoutDuration",   						       "lockOutObservationWindow",  @@ -886,42 +886,42 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,  	switch (r->in.level) {  	case 1:  		return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info1); +						 &r->out.info->info1);  	case 2: -		return dcesrv_samr_info_DomInfo2(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info2); +		return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,  +							      &r->out.info->general);  	case 3:  		return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info3); +						 &r->out.info->info3);  	case 4: -		return dcesrv_samr_info_DomInfo4(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info4); +		return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,  +							  &r->out.info->oem);  	case 5:  		return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info5); +						 &r->out.info->info5);  	case 6:  		return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info6); +						 &r->out.info->info6);  	case 7:  		return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info7); +						 &r->out.info->info7);  	case 8:  		return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info8); +						 &r->out.info->info8);  	case 9:  		return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info9); +						 &r->out.info->info9);  	case 11: -		return dcesrv_samr_info_DomInfo11(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info11); +		return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,  +							       &r->out.info->general2);  	case 12:  		return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info12); +						  &r->out.info->info12);  	case 13:  		return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,  -					  &r->out.info->info13); +						  &r->out.info->info13);  	} - +	  	return NT_STATUS_INVALID_INFO_CLASS;  } @@ -962,10 +962,10 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA  		SET_INT64  (msg, info1.min_password_age,       "minPwdAge");  		break;  	case 3: -		SET_UINT64  (msg, info3.force_logoff_time,      "forceLogoff"); +		SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");  		break;  	case 4: -		SET_STRING(msg, info4.comment,          "comment"); +		SET_STRING(msg, oem.oem_information,           "oEMInformation");  		break;  	case 6: @@ -2997,7 +2997,7 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA  	case 1:  	{  		static const char * const attrs2[] = {"sAMAccountName", "displayName", -						      "primaryGroupID", "description", +						      "primaryroupID", "description",  						      "comment", NULL};  		attrs = attrs2;  		break; diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6eb47c8595..4b310381ef 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -244,6 +244,7 @@ def provision_paths_from_lp(lp, dnsdomain):      paths.templates = os.path.join(paths.private_dir, "templates.ldb")      paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")      paths.namedconf = os.path.join(paths.private_dir, "named.conf") +    paths.namedtxt = os.path.join(paths.private_dir, "named.txt")      paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")      paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")      paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") @@ -1043,6 +1044,7 @@ def provision(setup_dir, message, session_info,          policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",                                      "{" + policyguid + "}")          os.makedirs(policy_path, 0755) +        open(os.path.join(policy_path, "GPT.INI"), 'w').write("")          os.makedirs(os.path.join(policy_path, "Machine"), 0755)          os.makedirs(os.path.join(policy_path, "User"), 0755)          if not os.path.isdir(paths.netlogon): @@ -1081,12 +1083,15 @@ def provision(setup_dir, message, session_info,                               hostip6=hostip6, hostname=names.hostname,                               dnspass=dnspass, realm=names.realm,                               domainguid=domainguid, hostguid=hostguid) -            message("Please install the zone located in %s into your DNS server" % paths.dns)              create_named_conf(paths.namedconf, setup_path, realm=names.realm, +                              dnsdomain=names.dnsdomain, private_dir=paths.private_dir) + +            create_named_txt(paths.namedtxt, setup_path, realm=names.realm,                                dnsdomain=names.dnsdomain, private_dir=paths.private_dir,                                keytab_name=paths.dns_keytab) -            message("See %s for example configuration statements for secure GSS-TSIG updates" % paths.namedconf) +            message("See %s for an example configuration include file for BIND" % paths.namedconf) +            message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)              create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,                               hostname=names.hostname, realm=names.realm) @@ -1376,7 +1381,7 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn,  def create_named_conf(path, setup_path, realm, dnsdomain, -                      private_dir, keytab_name): +                      private_dir):      """Write out a file containing zone statements suitable for inclusion in a      named.conf file (including GSS-TSIG configuration). @@ -1392,8 +1397,28 @@ def create_named_conf(path, setup_path, realm, dnsdomain,              "DNSDOMAIN": dnsdomain,              "REALM": realm,              "REALM_WC": "*." + ".".join(realm.split(".")[1:]), +            "PRIVATE_DIR": private_dir +            }) + +def create_named_txt(path, setup_path, realm, dnsdomain, +                      private_dir, keytab_name): +    """Write out a file containing zone statements suitable for inclusion in a +    named.conf file (including GSS-TSIG configuration). +     +    :param path: Path of the new named.conf file. +    :param setup_path: Setup path function. +    :param realm: Realm name +    :param dnsdomain: DNS Domain name +    :param private_dir: Path to private directory +    :param keytab_name: File name of DNS keytab file +    """ + +    setup_file(setup_path("named.txt"), path, { +            "DNSDOMAIN": dnsdomain, +            "REALM": realm,              "DNS_KEYTAB": keytab_name,              "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), +            "PRIVATE_DIR": private_dir          })  def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): diff --git a/source4/setup/named.conf b/source4/setup/named.conf index 4f98bbd914..0b087069c7 100644 --- a/source4/setup/named.conf +++ b/source4/setup/named.conf @@ -1,12 +1,15 @@ +# This file should be included in your main BIND configuration file  # -# Insert these snippets into your named.conf or bind.conf to configure -# the BIND nameserver. -# +# For example with +# include "${PRIVATE_DIR}/named.conf"; -# You should always include the actual forward zone configuration:  zone "${DNSDOMAIN}." IN {  	type master; -	file "${DNSDOMAIN}.zone"; +	file "${PRIVATE_DIR}/${DNSDOMAIN}.zone"; +	/* +	 * Attention: Not all BIND versions support "ms-self". The instead use +	 * of allow-update { any; }; is another, but less secure possibility. +	 */  	update-policy {  		/*  		 * A rather long description here, as the "ms-self" option does @@ -44,6 +47,8 @@ zone "${DNSDOMAIN}." IN {  # The reverse zone configuration is optional.  The following example assumes a  # subnet of 192.168.123.0/24: + +/*  zone "123.168.192.in-addr.arpa" in {  	type master;  	file "123.168.192.in-addr.arpa.zone"; @@ -51,54 +56,12 @@ zone "123.168.192.in-addr.arpa" in {  		grant ${REALM_WC} wildcard *.123.168.192.in-addr.arpa. PTR;  	};  }; +*/ +  # Note that the reverse zone file is not created during the provision process. -# The most recent BIND version (9.5.0a5 or later) supports secure GSS-TSIG +# The most recent BIND versions (9.5.0a5 or later) support secure GSS-TSIG  # updates.  If you are running an earlier version of BIND, or if you do not wish  # to use secure GSS-TSIG updates, you may remove the update-policy sections in  # both examples above. -# If you are running a capable version of BIND and you wish to support secure -# GSS-TSIG updates, you must make the following configuration changes: - -# - Insert the following lines into the options {} section of your named.conf -# file: -tkey-gssapi-credential "DNS/${DNSDOMAIN}"; -tkey-domain "${REALM}"; - -# - Modify BIND init scripts to pass the location of the generated keytab file. -# Fedora 8 & later provide a variable named KEYTAB_FILE in /etc/sysconfig/named -# for this purpose: -KEYTAB_FILE="${DNS_KEYTAB_ABS}" -# Note that the Fedora scripts translate KEYTAB_FILE behind the scenes into a -# variable named KRB5_KTNAME, which is ultimately passed to the BIND daemon.  If -# your distribution does not provide a variable like KEYTAB_FILE to pass a -# keytab file to the BIND daemon, a workaround is to place the following line in -# BIND's sysconfig file or in the init script for BIND: -export KRB5_KTNAME="${DNS_KEYTAB_ABS}" - -# - Set appropriate ownership and permissions on the ${DNS_KEYTAB} file.  Note -# that most distributions have BIND configured to run under a non-root user -# account.  For example, Fedora 9 runs BIND as the user "named" once the daemon -# relinquishes its rights.  Therefore, the file ${DNS_KEYTAB} must be readable -# by the user that BIND run as.  If BIND is running as a non-root user, the -# "${DNS_KEYTAB}" file must have its permissions altered to allow the daemon to -# read it.  Under Fedora 9, execute the following commands: -chgrp named ${DNS_KEYTAB_ABS} -chmod g+r ${DNS_KEYTAB_ABS} - -# - Ensure the BIND zone file(s) that will be dynamically updated are in a -# directory where the BIND daemon can write.  When BIND performs dynamic -# updates, it not only needs to update the zone file itself but it must also -# create a journal (.jnl) file to track the dynamic updates as they occur. -# Under Fedora 9, the /var/named directory can not be written to by the "named" -# user.  However, the directory /var/named/dynamic directory does provide write -# access.  Therefore the zone files were placed under the /var/named/dynamic -# directory.  The file directives in both example zone statements at the -# beginning of this file were changed by prepending the directory "dynamic/". - -# - If SELinux is enabled, ensure that all files have the appropriate SELinux -# file contexts.  The ${DNS_KEYTAB} file must be accessible by the BIND daemon -# and should have a SELinux type of named_conf_t.  This can be set with the -# following command: -chcon -t named_conf_t ${DNS_KEYTAB_ABS} diff --git a/source4/setup/named.txt b/source4/setup/named.txt new file mode 100644 index 0000000000..c1e6b3a9ee --- /dev/null +++ b/source4/setup/named.txt @@ -0,0 +1,46 @@ +# Additional informations for DNS setup using BIND + +# If you are running a capable version of BIND and you wish to support secure +# GSS-TSIG updates, you must make the following configuration changes: + +# - Insert the following lines into the options {} section of your named.conf +# file: +tkey-gssapi-credential "DNS/${DNSDOMAIN}"; +tkey-domain "${REALM}"; + +# - Modify BIND init scripts to pass the location of the generated keytab file. +# Fedora 8 & later provide a variable named KEYTAB_FILE in /etc/sysconfig/named +# for this purpose: +KEYTAB_FILE="${DNS_KEYTAB_ABS}" +# Note that the Fedora scripts translate KEYTAB_FILE behind the scenes into a +# variable named KRB5_KTNAME, which is ultimately passed to the BIND daemon.  If +# your distribution does not provide a variable like KEYTAB_FILE to pass a +# keytab file to the BIND daemon, a workaround is to place the following line in +# BIND's sysconfig file or in the init script for BIND: +export KRB5_KTNAME="${DNS_KEYTAB_ABS}" + +# - Set appropriate ownership and permissions on the ${DNS_KEYTAB} file.  Note +# that most distributions have BIND configured to run under a non-root user +# account.  For example, Fedora 9 runs BIND as the user "named" once the daemon +# relinquishes its rights.  Therefore, the file ${DNS_KEYTAB} must be readable +# by the user that BIND run as.  If BIND is running as a non-root user, the +# "${DNS_KEYTAB}" file must have its permissions altered to allow the daemon to +# read it.  Under Fedora 9, execute the following commands: +chgrp named ${DNS_KEYTAB_ABS} +chmod g+r ${DNS_KEYTAB_ABS} + +# - Ensure the BIND zone file(s) that will be dynamically updated are in a +# directory where the BIND daemon can write.  When BIND performs dynamic +# updates, it not only needs to update the zone file itself but it must also +# create a journal (.jnl) file to track the dynamic updates as they occur. +# Under Fedora 9, the /var/named directory can not be written to by the "named" +# user.  However, the directory /var/named/dynamic directory does provide write +# access.  Therefore the zone files were placed under the /var/named/dynamic +# directory.  The file directives in both example zone statements at the +# beginning of this file were changed by prepending the directory "dynamic/". + +# - If SELinux is enabled, ensure that all files have the appropriate SELinux +# file contexts.  The ${DNS_KEYTAB} file must be accessible by the BIND daemon +# and should have a SELinux type of named_conf_t.  This can be set with the +# following command: +chcon -t named_conf_t ${DNS_KEYTAB_ABS} diff --git a/source4/setup/provision.zone b/source4/setup/provision.zone index 28c1c29762..17ae3bb47a 100644 --- a/source4/setup/provision.zone +++ b/source4/setup/provision.zone @@ -14,10 +14,12 @@ ${HOSTIP6_BASE_LINE}  ;  ${HOSTIP6_HOST_LINE}  ${HOSTNAME}		IN A	${HOSTIP} -${HOSTGUID}._msdcs	IN CNAME ${HOSTNAME} +gc._msdcs		IN CNAME	${HOSTNAME} +${HOSTGUID}._msdcs	IN CNAME	${HOSTNAME}  ;  ; global catalog servers  _gc._tcp		IN SRV 0 100 3268	${HOSTNAME} +_gc._tcp.${DEFAULTSITE}._sites	IN SRV 0 100 3268	${HOSTNAME}  _ldap._tcp.gc._msdcs	IN SRV 0 100 389	${HOSTNAME}  _ldap._tcp.${DEFAULTSITE}._sites.gc._msdcs	IN SRV 0 100 389 ${HOSTNAME}  ; @@ -25,12 +27,15 @@ _ldap._tcp.${DEFAULTSITE}._sites.gc._msdcs	IN SRV 0 100 389 ${HOSTNAME}  _ldap._tcp		IN SRV 0 100 389	${HOSTNAME}  _ldap._tcp.dc._msdcs	IN SRV 0 100 389	${HOSTNAME}  _ldap._tcp.pdc._msdcs	IN SRV 0 100 389	${HOSTNAME} +_ldap._tcp.${DOMAINGUID}	IN SRV 0 100 389	${HOSTNAME}  _ldap._tcp.${DOMAINGUID}.domains._msdcs		IN SRV 0 100 389 ${HOSTNAME} +_ldap._tcp.${DEFAULTSITE}._sites		IN SRV 0 100 389 ${HOSTNAME}  _ldap._tcp.${DEFAULTSITE}._sites.dc._msdcs	IN SRV 0 100 389 ${HOSTNAME}  ;  ; krb5 servers  _kerberos._tcp		IN SRV 0 100 88		${HOSTNAME}  _kerberos._tcp.dc._msdcs	IN SRV 0 100 88	${HOSTNAME} +_kerberos._tcp.${DEFAULTSITE}._sites	IN SRV 0 100 88	${HOSTNAME}  _kerberos._tcp.${DEFAULTSITE}._sites.dc._msdcs	IN SRV 0 100 88 ${HOSTNAME}  _kerberos._udp		IN SRV 0 100 88		${HOSTNAME}  ; MIT kpasswd likes to lookup this name on password change diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index 21d17c5caa..3e129e4f6b 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -3,9 +3,15 @@  #  ## Samba4 OID allocation from Samba3's examples/LDAP/samba.schema  ## 1.3.6.1.4.1.7165.4.1.x - attributetypes +  ## 1.3.6.1.4.1.7165.4.2.x - objectclasses +  ## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls +### see dsdb/samdb/samdb.h +  ## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations +### see dsdb/samdb/samdb.h +  ## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track  #  # diff --git a/source4/setup/slapd.conf b/source4/setup/slapd.conf index 495847f7fe..4dcfd2aba7 100644 --- a/source4/setup/slapd.conf +++ b/source4/setup/slapd.conf @@ -32,6 +32,7 @@ access to dn.subtree="cn=samba"  access to dn.subtree="${DOMAINDN}"         by dn=cn=samba-admin,cn=samba manage +       by dn=cn=manager manage         by * none  password-hash   {CLEARTEXT} @@ -40,6 +41,8 @@ include ${LDAPDIR}/modules.conf  defaultsearchbase ${DOMAINDN} +rootdn cn=Manager +  ${REFINT_CONFIG}  ${MEMBEROF_CONFIG} @@ -47,6 +50,7 @@ ${MEMBEROF_CONFIG}  database	ldif  suffix		cn=Samba  directory       ${LDAPDIR}/db/samba +rootdn          cn=Manager,cn=Samba  database        hdb diff --git a/source4/torture/rpc/dssync.c b/source4/torture/rpc/dssync.c index 053f78e99b..2930a9b1f9 100644 --- a/source4/torture/rpc/dssync.c +++ b/source4/torture/rpc/dssync.c @@ -23,6 +23,7 @@  #include "includes.h"  #include "lib/cmdline/popt_common.h"  #include "librpc/gen_ndr/ndr_drsuapi_c.h" +#include "librpc/gen_ndr/ndr_drsblobs.h"  #include "libcli/cldap/cldap.h"  #include "libcli/ldap/ldap_client.h"  #include "torture/torture.h" @@ -104,7 +105,7 @@ static struct DsSyncTest *test_create_context(struct torture_context *tctx)  	our_bind_info28->supported_extensions	= 0xFFFFFFFF;  	our_bind_info28->supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;  	our_bind_info28->site_guid		= GUID_zero(); -	our_bind_info28->u1			= 0; +	our_bind_info28->pid			= 0;  	our_bind_info28->repl_epoch		= 1;  	our_bind_info_ctr			= &ctx->admin.drsuapi.our_bind_info_ctr; @@ -153,7 +154,7 @@ static struct DsSyncTest *test_create_context(struct torture_context *tctx)  		our_bind_info28->supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;  	}  	our_bind_info28->site_guid		= GUID_zero(); -	our_bind_info28->u1			= 508; +	our_bind_info28->pid			= 0;  	our_bind_info28->repl_epoch		= 0;  	our_bind_info_ctr			= &ctx->new_dc.drsuapi.our_bind_info_ctr; @@ -210,13 +211,25 @@ static bool _test_DsBind(struct torture_context *tctx,  			info24 = &b->req.out.bind_info->info.info24;  			b->peer_bind_info28.supported_extensions= info24->supported_extensions;  			b->peer_bind_info28.site_guid		= info24->site_guid; -			b->peer_bind_info28.u1			= info24->u1; +			b->peer_bind_info28.pid			= info24->pid;  			b->peer_bind_info28.repl_epoch		= 0;  			break;  		} +		case 48: { +			struct drsuapi_DsBindInfo48 *info48; +			info48 = &b->req.out.bind_info->info.info48; +			b->peer_bind_info28.supported_extensions= info48->supported_extensions; +			b->peer_bind_info28.site_guid		= info48->site_guid; +			b->peer_bind_info28.pid			= info48->pid; +			b->peer_bind_info28.repl_epoch		= info48->repl_epoch; +			break; +		}  		case 28:  			b->peer_bind_info28 = b->req.out.bind_info->info.info28;  			break; +		default: +			printf("DsBind - warning: unknown BindInfo length: %u\n", +			       b->req.out.bind_info->length);  		}  	} @@ -514,6 +527,8 @@ static void test_analyse_objects(struct torture_context *tctx,  			DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",  				    name, (long)enc_data->length, (long)plain_data.length));  			if (plain_data.length) { +				enum ndr_err_code ndr_err; +				struct supplementalCredentialsBlob scb;  				dump_data(0, plain_data.data, plain_data.length);  				if (save_values_dir) {  					char *fname; @@ -529,6 +544,13 @@ static void test_analyse_objects(struct torture_context *tctx,  					}  					talloc_free(fname);  				} + +				ndr_err = ndr_pull_struct_blob_all(&plain_data, tctx, +					   lp_iconv_convenience(tctx->lp_ctx), &scb, +					   (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob); +				if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +					NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb); +				}  			} else {  				dump_data(0, enc_data->data, enc_data->length);  			} diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index a4e702f759..e6102f0a82 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -1822,6 +1822,19 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,  	printf("\nTesting EnumTrustDom\n"); +	r.in.handle = handle; +	r.in.resume_handle = &resume_handle; +	r.in.max_size = 0; +	r.out.domains = &domains; +	r.out.resume_handle = &resume_handle; +	 +	enum_status = dcerpc_lsa_EnumTrustDom(p, mem_ctx, &r); +	 +	if (!(NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES) || NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES))) { +		printf("EnumTrustDom of zero size failed - %s\n", nt_errstr(enum_status)); +		return false; +	} +		  	do {  		r.in.handle = handle;  		r.in.resume_handle = &resume_handle; @@ -1848,12 +1861,30 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,  			return false;  		} +		if (domains.count == 0) { +			printf("EnumTrustDom failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n"); +			return false; +		} +  		ret &= test_query_each_TrustDom(p, mem_ctx, handle, &domains);  	} while ((NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES)));  	printf("\nTesting EnumTrustedDomainsEx\n"); +	r_ex.in.handle = handle; +	r_ex.in.resume_handle = &resume_handle; +	r_ex.in.max_size = LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER * 3; +	r_ex.out.domains = &domains_ex; +	r_ex.out.resume_handle = &resume_handle; +	 +	enum_status = dcerpc_lsa_EnumTrustedDomainsEx(p, mem_ctx, &r_ex); +	 +	if (!(NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES) || NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES))) { +		printf("EnumTrustedDomainEx of zero size failed - %s\n", nt_errstr(enum_status)); +		return false; +	} +		  	resume_handle = 0;  	do {  		r_ex.in.handle = handle; @@ -1884,6 +1915,11 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,  			return false;  		} +		if (domains_ex.count == 0) { +			printf("EnumTrustDomainEx failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n"); +			return false; +		} +  		ret &= test_query_each_TrustDomEx(p, mem_ctx, handle, &domains_ex);  	} while ((NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES))); @@ -1906,6 +1942,10 @@ static bool test_CreateTrustedDomain(struct dcerpc_pipe *p,  	printf("Testing CreateTrustedDomain for 12 domains\n"); +	if (!test_EnumTrustDom(p, mem_ctx, handle)) { +		ret = false; +	} +	  	for (i=0; i< 12; i++) {  		char *trust_name = talloc_asprintf(mem_ctx, "torturedom%02d", i);  		char *trust_sid = talloc_asprintf(mem_ctx, "S-1-5-21-97398-379795-100%02d", i); diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 55c75ba270..6afda6e9b5 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -3595,17 +3595,17 @@ static bool test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,  		switch (r.in.level) {  		case 1:  		case 4: -			if (dom_info.out.info->info2.num_users < r.in.start_idx) { +			if (dom_info.out.info->general.num_users < r.in.start_idx) {  				printf("QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n", -				       r.in.start_idx, dom_info.out.info->info2.num_groups, -				       dom_info.out.info->info2.domain_name.string); +				       r.in.start_idx, dom_info.out.info->general.num_groups, +				       dom_info.out.info->general.domain_name.string);  				ret = false;  			}  			if (!seen_testuser) {  				struct policy_handle user_handle;  				if (NT_STATUS_IS_OK(test_OpenUser_byname(p, mem_ctx, handle, TEST_ACCOUNT_NAME, &user_handle))) {  					printf("Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n",  -					       dom_info.out.info->info2.domain_name.string); +					       dom_info.out.info->general.domain_name.string);  					ret = false;  					test_samr_handle_Close(p, mem_ctx, &user_handle);  				} @@ -3613,10 +3613,10 @@ static bool test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,  			break;  		case 3:  		case 5: -			if (dom_info.out.info->info2.num_groups != r.in.start_idx) { +			if (dom_info.out.info->general.num_groups != r.in.start_idx) {  				printf("QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n", -				       r.in.start_idx, dom_info.out.info->info2.num_groups, -				       dom_info.out.info->info2.domain_name.string); +				       r.in.start_idx, dom_info.out.info->general.num_groups, +				       dom_info.out.info->general.domain_name.string);  				ret = false;  			} @@ -3745,7 +3745,7 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,  	s.in.level = 4;  	s.in.info = talloc(mem_ctx, union samr_DomainInfo); -	s.in.info->info4.comment.string = domain_comment; +	s.in.info->oem.oem_information.string = domain_comment;  	status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s);  	if (!NT_STATUS_IS_OK(status)) {  		printf("SetDomainInfo level %u (set comment) failed - %s\n",  @@ -3769,26 +3769,26 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,  		switch (levels[i]) {  		case 2: -			if (strcmp(r.out.info->info2.comment.string, domain_comment) != 0) { -				printf("QueryDomainInfo level %u returned different comment (%s, expected %s)\n", -				       levels[i], r.out.info->info2.comment.string, domain_comment); +			if (strcmp(r.out.info->general.oem_information.string, domain_comment) != 0) { +				printf("QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", +				       levels[i], r.out.info->general.oem_information.string, domain_comment);  				ret = false;  			} -			if (!r.out.info->info2.primary.string) { +			if (!r.out.info->general.primary.string) {  				printf("QueryDomainInfo level %u returned no PDC name\n",  				       levels[i]);  				ret = false; -			} else if (r.out.info->info2.role == SAMR_ROLE_DOMAIN_PDC) { -				if (dcerpc_server_name(p) && strcasecmp_m(dcerpc_server_name(p), r.out.info->info2.primary.string) != 0) { +			} else if (r.out.info->general.role == SAMR_ROLE_DOMAIN_PDC) { +				if (dcerpc_server_name(p) && strcasecmp_m(dcerpc_server_name(p), r.out.info->general.primary.string) != 0) {  					printf("QueryDomainInfo level %u returned different PDC name (%s) compared to server name (%s), despite claiming to be the PDC\n", -					       levels[i], r.out.info->info2.primary.string, dcerpc_server_name(p)); +					       levels[i], r.out.info->general.primary.string, dcerpc_server_name(p));  				}  			}  			break;  		case 4: -			if (strcmp(r.out.info->info4.comment.string, domain_comment) != 0) { -				printf("QueryDomainInfo level %u returned different comment (%s, expected %s)\n", -				       levels[i], r.out.info->info4.comment.string, domain_comment); +			if (strcmp(r.out.info->oem.oem_information.string, domain_comment) != 0) { +				printf("QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", +				       levels[i], r.out.info->oem.oem_information.string, domain_comment);  				ret = false;  			}  			break; @@ -3800,9 +3800,9 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,  			}  			break;  		case 11: -			if (strcmp(r.out.info->info11.info2.comment.string, domain_comment) != 0) { +			if (strcmp(r.out.info->general2.general.oem_information.string, domain_comment) != 0) {  				printf("QueryDomainInfo level %u returned different comment (%s, expected %s)\n", -				       levels[i], r.out.info->info11.info2.comment.string, domain_comment); +				       levels[i], r.out.info->general2.general.oem_information.string, domain_comment);  				ret = false;  			}  			break; diff --git a/source4/torture/rpc/samsync.c b/source4/torture/rpc/samsync.c index 7114756460..1e76de1dd2 100644 --- a/source4/torture/rpc/samsync.c +++ b/source4/torture/rpc/samsync.c @@ -346,9 +346,9 @@ static bool samsync_handle_domain(TALLOC_CTX *mem_ctx, struct samsync_state *sam  	TEST_STRING_EQUAL(q[5].out.info->info5.domain_name, domain->domain_name); -	TEST_STRING_EQUAL(q[2].out.info->info2.comment, domain->comment); -	TEST_STRING_EQUAL(q[4].out.info->info4.comment, domain->comment); -	TEST_TIME_EQUAL(q[2].out.info->info2.force_logoff_time, domain->force_logoff_time); +	TEST_STRING_EQUAL(q[2].out.info->general.oem_information, domain->oem_information); +	TEST_STRING_EQUAL(q[4].out.info->oem.oem_information, domain->oem_information); +	TEST_TIME_EQUAL(q[2].out.info->general.force_logoff_time, domain->force_logoff_time);  	TEST_TIME_EQUAL(q[3].out.info->info3.force_logoff_time, domain->force_logoff_time);  	TEST_TIME_EQUAL(q[1].out.info->info1.min_password_length, domain->min_password_length); @@ -1487,7 +1487,7 @@ bool torture_rpc_samsync(struct torture_context *torture)  	s.in.level = 4;  	s.in.info = talloc(mem_ctx, union samr_DomainInfo); -	s.in.info->info4.comment.string +	s.in.info->oem.oem_information.string  		= talloc_asprintf(mem_ctx,   				  "Tortured by Samba4: %s",   				  timestring(mem_ctx, time(NULL))); diff --git a/source4/winbind/wb_cmd_list_trustdom.c b/source4/winbind/wb_cmd_list_trustdom.c index 8d0c1bd947..fe98ce2f6a 100644 --- a/source4/winbind/wb_cmd_list_trustdom.c +++ b/source4/winbind/wb_cmd_list_trustdom.c @@ -159,7 +159,8 @@ static void cmd_list_trustdoms_recv_doms(struct rpc_request *req)  			state->r.out.domains->domains[i].sid);  	} -	if (NT_STATUS_IS_OK(state->ctx->status)) { +	if (NT_STATUS_IS_OK(state->ctx->status) || NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_NO_MORE_ENTRIES)) { +		state->ctx->status = NT_STATUS_OK;  		composite_done(state->ctx);  		return;  	}  | 
