diff options
37 files changed, 1323 insertions, 350 deletions
diff --git a/packaging/Fedora/samba4.spec b/packaging/Fedora/samba4.spec index 4e86050dcf..45d1429362 100644 --- a/packaging/Fedora/samba4.spec +++ b/packaging/Fedora/samba4.spec @@ -11,7 +11,6 @@ Summary: The Samba4 CIFS and AD client and server suite Name: samba4 -Epoch: 0 Version: 4.0.0 Release: 0.%{main_release}.alpha%{alpha_version}%{?dist} License: GPLv3+, LGPLv3+, BSD @@ -25,7 +24,7 @@ Source1: %{name}.log Source4: %{name}.sysconfig Source5: %{name}.init -Requires(pre): %{name}-common = %{epoch}:%{version}-%{release} +Requires(pre): %{name}-common = %{version}-%{release} Requires: pam >= 0:0.64 Requires: logrotate >= 0:3.4 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -33,7 +32,7 @@ Requires(pre): /usr/sbin/groupadd Requires(post): /sbin/chkconfig, /sbin/service Requires(preun): /sbin/chkconfig, /sbin/service BuildRequires: pam-devel, readline-devel, ncurses-devel, libacl-devel, e2fsprogs-devel -BuildRequires: popt-devel, libattr-devel, libaio-devel, sed, ldconfig +BuildRequires: popt-devel, libattr-devel, libaio-devel, sed BuildRequires: perl(ExtUtils::MakeMaker) BuildRequires: libtalloc-devel >= %{talloc_version} BuildRequires: libtdb-devel >= %{tdb_version} @@ -48,8 +47,8 @@ by Windows 2000 and above. %package client Summary: Samba client programs Group: Applications/System -Requires: %{name}-common = %{epoch}:%{version}-%{release} -Requires: %{name}-libs = %{epoch}:%{version}-%{release} +Requires: %{name}-common = %{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} %description client The %{name}-client package provides some SMB/CIFS clients to complement @@ -59,10 +58,6 @@ of SMB/CIFS shares and printing to SMB/CIFS printers. %package libs Summary: Samba libraries Group: Applications/System -Requires: libtdb >= 0:%{tdb_version} -Requires: libtalloc >= 0:%{talloc_version} -Requires(post): /sbin/ldconfig -Requires(postun): /sbin/ldconfig %description libs The %{name}-libs package contains the libraries needed by programs @@ -71,7 +66,7 @@ that link against the SMB, RPC and other protocols provided by the Samba suite. %package python Summary: Samba python libraries Group: Applications/System -Requires: %{name}-libs = %{epoch}:%{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} %description python The %{name}-python package contains the python libraries needed by programs @@ -80,7 +75,7 @@ that use SMB, RPC and other Samba provided protocols in python programs/ %package devel Summary: Developer tools for Samba libraries Group: Development/Libraries -Requires: %{name}-libs = %{epoch}:%{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} %description devel The %{name}-devel package contains the header files for the libraries @@ -99,8 +94,8 @@ and Wireshark to parse IDL and similar protocols %package common Summary: Files used by both Samba servers and clients Group: Applications/System -Requires: %{name}-libs = %{epoch}:%{version}-%{release} -Requires(post): /sbin/chkconfig, /sbin/service, coreutils +Requires: %{name}-libs = %{version}-%{release} +Requires(post): /sbin/chkconfig, /sbin/service Requires(preun): /sbin/chkconfig, /sbin/service %description common @@ -110,7 +105,7 @@ packages of Samba. %package winbind Summary: Samba winbind Group: Applications/System -Requires: %{name} = %{epoch}:%{version}-%{release} +Requires: %{name} = %{version}-%{release} %description winbind The samba-winbind package provides the winbind NSS library, and some diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c index a880486f0f..c4c58398c3 100644 --- a/source4/auth/credentials/credentials_krb5.c +++ b/source4/auth/credentials/credentials_krb5.c @@ -360,6 +360,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, struct gssapi_creds_container *gcc; struct ccache_container *ccache; gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + krb5_enctype *etypes = NULL; if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && cred->client_gss_creds_obtained > CRED_UNINITIALISED) { @@ -391,6 +392,28 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, return ret; } + /* transfer the enctypes from the smb_krb5_context to the gssapi layer */ + min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context, + &etypes); + if (min_stat == 0) { + OM_uint32 num_ktypes; + + for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); + + maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, + num_ktypes, etypes); + krb5_xfree (etypes); + if (maj_stat) { + talloc_free(gcc); + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + return ret; + } + } + /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, GSS_KRB5_CRED_NO_CI_FLAGS_X, diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index cc0d40469e..205d8a0f9b 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -1034,35 +1034,22 @@ static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_securit = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); OM_uint32 maj_stat, min_stat; gss_buffer_desc input_token, output_token; - int conf_state; - ssize_t sig_length = 0; input_token.length = length; input_token.value = discard_const_p(uint8_t *, data); - maj_stat = gss_wrap(&min_stat, + maj_stat = gss_get_mic(&min_stat, gensec_gssapi_state->gssapi_context, - 0, GSS_C_QOP_DEFAULT, &input_token, - &conf_state, &output_token); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS Wrap failed: %s\n", + DEBUG(1, ("GSS GetMic failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); return NT_STATUS_ACCESS_DENIED; } - if (output_token.length < input_token.length) { - DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n", - (long)output_token.length, (long)length)); - return NT_STATUS_INTERNAL_ERROR; - } - - /* Caller must pad to right boundary */ - sig_length = output_token.length - input_token.length; - - *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length); + *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length); dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length); @@ -1080,39 +1067,29 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); OM_uint32 maj_stat, min_stat; - gss_buffer_desc input_token, output_token; - int conf_state; + gss_buffer_desc input_token; + gss_buffer_desc input_message; gss_qop_t qop_state; - DATA_BLOB in; dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length); - in = data_blob_talloc(mem_ctx, NULL, sig->length + length); + input_message.length = length; + input_message.value = data; - memcpy(in.data, sig->data, sig->length); - memcpy(in.data + sig->length, data, length); + input_token.length = sig->length; + input_token.value = sig->data; - input_token.length = in.length; - input_token.value = in.data; - - maj_stat = gss_unwrap(&min_stat, + maj_stat = gss_verify_mic(&min_stat, gensec_gssapi_state->gssapi_context, + &input_message, &input_token, - &output_token, - &conf_state, &qop_state); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS UnWrap failed: %s\n", + DEBUG(1, ("GSS VerifyMic failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); return NT_STATUS_ACCESS_DENIED; } - if (output_token.length != length) { - return NT_STATUS_INTERNAL_ERROR; - } - - gss_release_buffer(&min_stat, &output_token); - return NT_STATUS_OK; } 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..69783aefa8 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,61 @@ 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 + */ + pkb->version = 3; + pkb3->salt.string = io->g.salt; + pkb3->num_keys = 2; + pkb3->keys = talloc_array(io->ac, + struct package_PrimaryKerberosKey3, + 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 +463,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 +516,124 @@ 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_PrimaryKerberosBlob *pkb) +{ + struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4; + struct supplementalCredentialsPackage *old_scp = NULL; + struct package_PrimaryKerberosBlob _old_pkb; + struct package_PrimaryKerberosCtr4 *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 + */ + pkb->version = 4; + pkb4->salt.string = io->g.salt; + pkb4->default_iteration_count = 4096; + pkb4->num_keys = 4; + + pkb4->keys = talloc_array(io->ac, + struct package_PrimaryKerberosKey4, + pkb4->num_keys); + if (!pkb4->keys) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + pkb4->keys[0].iteration_count = 4096; + pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96; + pkb4->keys[0].value = &io->g.aes_256; + pkb4->keys[1].iteration_count = 4096; + pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96; + pkb4->keys[1].value = &io->g.aes_128; + pkb4->keys[2].iteration_count = 4096; + pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5; + pkb4->keys[2].value = &io->g.des_md5; + pkb4->keys[3].iteration_count = 4096; + 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_keys = 0; + pkb4->old_keys = NULL; + pkb4->num_older_keys = 0; + pkb4->older_keys = 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-Newer-Keys 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_PrimaryKerberosBlob); + 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_PrimaryKerberosBlob: %s", + nt_errstr(status)); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (_old_pkb.version != 4) { + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_primary_kerberos_newer: " + "package_PrimaryKerberosBlob 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_keys = old_pkb4->num_keys; + pkb4->old_keys = old_pkb4->keys; + pkb4->num_older_keys = old_pkb4->num_old_keys; + pkb4->older_keys = old_pkb4->old_keys; return LDB_SUCCESS; } @@ -845,30 +975,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_PrimaryKerberosBlob 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 +1028,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 +1041,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_PrimaryKerberosBlob); + 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 +1154,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 +1191,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 +1220,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 +1246,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 +1304,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 +1325,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 +1343,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..ebc90d4cf3 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -263,9 +263,10 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req) struct ldb_request *down_req; int ret; - /* see if its for the rootDSE */ + /* see if its for the rootDSE - only a base search on the "" DN qualifies */ if (req->op.search.scope != LDB_SCOPE_BASE || ( ! ldb_dn_is_null(req->op.search.base))) { + /* Otherwise, pass down to the rest of the stack */ return ldb_next_request(module, req); } @@ -391,9 +392,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..3e92671fa0 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -90,4 +90,10 @@ struct dsdb_pdc_fsmo { struct ldb_dn *master_dn; }; +/* + * the schema_dn is passed as struct ldb_dn in + * req->op.extended.data + */ +#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..9b8959466d 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -268,18 +268,152 @@ 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; + 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: %s\n", + win_errstr(status))); + 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; + } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { + /* error */ + DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n", + win_errstr(status))); + talloc_free(mem_ctx); + return status; + } + + /* Create the new mapping for the prefix of full_oid */ + 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: %s\n", + win_errstr(status))); + talloc_free(mem_ctx); + return status; + } + + /* Update prefixMap in ldb*/ + status = dsdb_write_prefixes_to_ldb(mem_ctx, ldb, num_prefixes, prefixes); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n", + win_errstr(status))); + 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; + + /* + * this is the algorithm we use to create new mappings for now + * + * TODO: find what algorithm windows use + */ + 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,56 +439,141 @@ 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, + uint32_t num_prefixes, + const struct dsdb_schema_oid_prefix *prefixes) { + struct ldb_message msg; + struct ldb_dn *schema_dn; + struct ldb_message_element el; + struct prefixMapBlob pm; + struct ldb_val ndr_blob; + enum ndr_err_code ndr_err; uint32_t i; + 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; + } - 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); + pm.version = PREFIX_MAP_VERSION_DSDB; + pm.ctr.dsdb.num_mappings = num_prefixes; + pm.ctr.dsdb.mappings = talloc_array(mem_ctx, + struct drsuapi_DsReplicaOIDMapping, + pm.ctr.dsdb.num_mappings); + if (!pm.ctr.dsdb.mappings) { + return WERR_NOMEM; + } - *out = val; - return WERR_OK; + for (i=0; i < num_prefixes; i++) { + pm.ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16; + pm.ctr.dsdb.mappings[i].oid.oid = talloc_strdup(pm.ctr.dsdb.mappings, prefixes[i].oid); } - return WERR_DS_NO_MSDS_INTID; + ndr_err = ndr_push_struct_blob(&ndr_blob, ldb, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + &pm, + (ndr_push_flags_fn_t)ndr_push_prefixMapBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + 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; } -/* - * 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_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes) { - /* - * 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; + 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 + }; + + schema_dn = samdb_schema_dn(ldb); + if (!schema_dn) { + DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n")); + return WERR_FOOBAR; + } + + 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; + } + + 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; + } + + 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; } #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \ @@ -1534,6 +1753,11 @@ int dsdb_set_global_schema(struct ldb_context *ldb) return ret; } + /* Keep a reference to this schema, just incase the global copy is replaced */ + if (talloc_reference(ldb, global_schema) == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; } @@ -1571,6 +1795,10 @@ void dsdb_make_schema_global(struct ldb_context *ldb) return; } + if (global_schema) { + talloc_unlink(talloc_autofree_context(), schema); + } + talloc_steal(talloc_autofree_context(), schema); global_schema = schema; diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 70e578ee0d..8f8ce3074b 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -190,9 +190,11 @@ 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; + bool newer_keys = false; struct package_PrimaryKerberosBlob _pkb; struct package_PrimaryKerberosCtr3 *pkb3 = NULL; + struct package_PrimaryKerberosCtr4 *pkb4 = NULL; uint32_t i; uint32_t allocated_keys = 0; @@ -221,35 +223,48 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context, goto out; } - for (i=0; i < scb.sub.num_packages; i++) { - if (scb.sub.packages[i].unknown1 != 0x00000001) { - continue; - } - - if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) != 0) { - continue; - } + if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) { + NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb); + ret = EINVAL; + goto out; + } - if (!scb.sub.packages[i].data || !scb.sub.packages[i].data[0]) { - continue; + for (i=0; i < scb.sub.num_packages; i++) { + if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) { + scpk = &scb.sub.packages[i]; + if (!scpk->data || !scpk->data[0]) { + scpk = NULL; + continue; + } + newer_keys = true; + 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 + */ } - - scp = &scb.sub.packages[i]; - break; } } - /* Primary:Kerberos element of supplementalCredentials */ - if (scp) { + /* + * Primary:Kerberos-Newer-Keys or Primary:Kerberos element + * of supplementalCredentials + */ + if (scpk) { 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)) { @@ -259,16 +274,27 @@ static krb5_error_code LDB_message2entry_keys(krb5_context context, goto out; } - if (_pkb.version != 3) { - krb5_set_error_string(context, "LDB_message2entry_keys: could not parse PrimaryKerberos not version 3"); - krb5_warnx(context, "LDB_message2entry_keys: could not parse PrimaryKerberos not version 3"); + if (newer_keys && _pkb.version != 4) { + krb5_set_error_string(context, "LDB_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4"); + krb5_warnx(context, "LDB_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4"); ret = EINVAL; goto out; } - - pkb3 = &_pkb.ctr.ctr3; - allocated_keys += pkb3->num_keys; + if (!newer_keys && _pkb.version != 3) { + krb5_set_error_string(context, "LDB_message2entry_keys: could not parse Primary:Kerberos not version 3"); + krb5_warnx(context, "LDB_message2entry_keys: could not parse Primary:Kerberos not version 3"); + ret = EINVAL; + goto out; + } + + if (_pkb.version == 4) { + pkb4 = &_pkb.ctr.ctr4; + allocated_keys += pkb4->num_keys; + } else if (_pkb.version == 3) { + pkb3 = &_pkb.ctr.ctr3; + allocated_keys += pkb3->num_keys; + } } if (allocated_keys == 0) { @@ -304,7 +330,70 @@ 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; + } + } + + /* TODO: maybe pass the iteration_count somehow... */ + + 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 +414,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/events/events_signal.c b/source4/lib/events/events_signal.c index 80a14acc11..652df53d4b 100644 --- a/source4/lib/events/events_signal.c +++ b/source4/lib/events/events_signal.c @@ -46,15 +46,15 @@ struct sigcounter { the poor design of signals means that this table must be static global */ static struct sig_state { - struct signal_event *sig_handlers[NUM_SIGNALS]; - struct sigaction *oldact[NUM_SIGNALS]; - struct sigcounter signal_count[NUM_SIGNALS]; + struct signal_event *sig_handlers[NUM_SIGNALS+1]; + struct sigaction *oldact[NUM_SIGNALS+1]; + struct sigcounter signal_count[NUM_SIGNALS+1]; struct sigcounter got_signal; int pipe_hack[2]; #ifdef SA_SIGINFO /* with SA_SIGINFO we get quite a lot of info per signal */ - siginfo_t *sig_info[NUM_SIGNALS]; - struct sigcounter sig_blocked[NUM_SIGNALS]; + siginfo_t *sig_info[NUM_SIGNALS+1]; + struct sigcounter sig_blocked[NUM_SIGNALS+1]; #endif } *sig_state; diff --git a/source4/lib/ldb/tools/cmdline.c b/source4/lib/ldb/tools/cmdline.c index c9c77c4e47..765d8b9edf 100644 --- a/source4/lib/ldb/tools/cmdline.c +++ b/source4/lib/ldb/tools/cmdline.c @@ -75,6 +75,7 @@ struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, #if (_SAMBA_BUILD_ >= 4) POPT_COMMON_SAMBA POPT_COMMON_CREDENTIALS + POPT_COMMON_CONNECTION POPT_COMMON_VERSION #endif { NULL } diff --git a/source4/lib/util/byteorder.h b/source4/lib/util/byteorder.h index 857bd1d50b..894beccabf 100644 --- a/source4/lib/util/byteorder.h +++ b/source4/lib/util/byteorder.h @@ -126,6 +126,8 @@ static __inline__ void st_le32(uint32_t *addr, const uint32_t val) __asm__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } #define HAVE_ASM_BYTEORDER 1 +#else +#define HAVE_ASM_BYTEORDER 0 #endif @@ -172,7 +174,7 @@ static __inline__ void st_le32(uint32_t *addr, const uint32_t val) #define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16_t)(val))) #define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32_t)(val))) -#else /* CAREFUL_ALIGNMENT */ +#else /* not CAREFUL_ALIGNMENT */ /* this handles things for architectures like the 386 that can handle alignment errors */ @@ -197,7 +199,7 @@ static __inline__ void st_le32(uint32_t *addr, const uint32_t val) #define SSVALS(buf,pos,val) SVALS_NC(buf,pos)=((int16_t)(val)) #define SIVALS(buf,pos,val) IVALS_NC(buf,pos)=((int32_t)(val)) -#endif /* CAREFUL_ALIGNMENT */ +#endif /* not CAREFUL_ALIGNMENT */ /* now the reverse routines - these are used in nmb packets (mostly) */ #define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) 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_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/dcerpc.idl b/source4/librpc/idl/dcerpc.idl index 57028ffcbf..e54bc2c29f 100644 --- a/source4/librpc/idl/dcerpc.idl +++ b/source4/librpc/idl/dcerpc.idl @@ -253,6 +253,7 @@ interface dcerpc const uint8 DCERPC_PFC_FLAG_FIRST = 0x01; /* First fragment */ const uint8 DCERPC_PFC_FLAG_LAST = 0x02; /* Last fragment */ const uint8 DCERPC_PFC_FLAG_PENDING_CANCEL = 0x04; /* Cancel was pending at sender */ + const uint8 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN = DCERPC_PFC_FLAG_PENDING_CANCEL; /* depends on the pdu type */ const uint8 DCERPC_PFC_FLAG_CONC_MPX = 0x10; /* supports concurrent multiplexing of a single connection. */ const uint8 DCERPC_PFC_FLAG_DID_NOT_EXECUTE = 0x20; /* on a fault it means the server hasn't done anything */ const uint8 DCERPC_PFC_FLAG_MAYBE = 0x40; /* `maybe' call semantics requested */ diff --git a/source4/librpc/idl/drsblobs.idl b/source4/librpc/idl/drsblobs.idl index f8cbdac8c5..adfc010237 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,31 +272,58 @@ 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; + } package_PrimaryKerberosKey3; 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]; + package_PrimaryKerberosKey3 keys[num_keys]; + package_PrimaryKerberosKey3 old_keys[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 struct { + [value(0)] uint16 reserved1; + [value(0)] uint16 reserved2; + [value(0)] uint32 reserved3; + uint32 iteration_count; + uint32 keytype; + [value((value?value->length:0))] uint32 value_len; + [relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value; + } package_PrimaryKerberosKey4; + + typedef struct { + uint16 num_keys; + [value(0)] uint16 num_service_keys; + uint16 num_old_keys; + uint16 num_older_keys; + package_PrimaryKerberosString salt; + uint32 default_iteration_count; + package_PrimaryKerberosKey4 keys[num_keys]; + package_PrimaryKerberosKey4 service_keys[num_service_keys]; + package_PrimaryKerberosKey4 old_keys[num_old_keys]; + package_PrimaryKerberosKey4 older_keys[num_older_keys]; + } package_PrimaryKerberosCtr4; + typedef [nodiscriminant] union { [case(3)] package_PrimaryKerberosCtr3 ctr3; + [case(4)] package_PrimaryKerberosCtr4 ctr4; } package_PrimaryKerberosCtr; typedef [public] struct { - [value(3)] uint32 version; + uint16 version; + [value(0)] uint16 flags; [switch_is(version)] package_PrimaryKerberosCtr ctr; } package_PrimaryKerberosBlob; 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/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/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 01a249ceb7..6114b2052c 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -631,12 +631,6 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, status = pvfs_access_check_create(pvfs, req, name, &access_mask); NT_STATUS_NOT_OK_RETURN(status); - if (io->generic.in.query_maximal_access) { - status = pvfs_access_maximal_allowed(pvfs, req, name, - &io->generic.out.maximal_access); - NT_STATUS_NOT_OK_RETURN(status); - } - /* check that the parent isn't opened with delete on close set */ status = pvfs_resolve_parent(pvfs, req, name, &parent); if (NT_STATUS_IS_OK(status)) { @@ -707,6 +701,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, goto cleanup_delete; } + if (io->generic.in.query_maximal_access) { + status = pvfs_access_maximal_allowed(pvfs, req, name, + &io->generic.out.maximal_access); + NT_STATUS_NOT_OK_RETURN(status); + } + /* form the lock context used for byte range locking and opendb locking */ status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key); diff --git a/source4/ntvfs/posix/xattr_system.c b/source4/ntvfs/posix/xattr_system.c index 7283d716b4..9a89f2a338 100644 --- a/source4/ntvfs/posix/xattr_system.c +++ b/source4/ntvfs/posix/xattr_system.c @@ -74,7 +74,7 @@ again: return NT_STATUS_NOT_FOUND; } else { - /* if not this was probably a legittimate error + /* if not this was probably a legitimate error * reset ret and errno to the correct values */ errno = EPERM; ret = -1; 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/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index d8dafd61f6..cb07f6e8ce 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -36,6 +36,8 @@ #include "libcli/security/security.h" #include "param/param.h" +#define SAMBA_ACCOC_GROUP 0x12345678 + extern const struct dcesrv_interface dcesrv_mgmt_interface; /* @@ -270,11 +272,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 +545,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 != SAMBA_ACCOC_GROUP) { return dcesrv_bind_nak(call, 0); } @@ -609,7 +631,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) pkt.u.bind_ack.max_xmit_frag = 0x2000; pkt.u.bind_ack.max_recv_frag = 0x2000; /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */ - pkt.u.bind_ack.assoc_group_id = 0x12345678; + pkt.u.bind_ack.assoc_group_id = SAMBA_ACCOC_GROUP; if (iface) { /* FIXME: Use pipe name as specified by endpoint instead of interface name */ pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name); 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/scripting/bin/mymachinepw b/source4/scripting/bin/mymachinepw new file mode 100755 index 0000000000..49a4245a3a --- /dev/null +++ b/source4/scripting/bin/mymachinepw @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# Unix SMB/CIFS implementation. +# Copyright (C) Volker Lendecke 2008 +# Copyright (C) Stefan Metzmacher 2008 +# +# Extract our own machine pw from secrets.ldb +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import samba.param as param, ldb, sys, getopt + +optlist, args = getopt.getopt(sys.argv[1:], "s:") + +conf = param.LoadParm() +loaded = False + +for o, v in optlist: + if o == "-s": + if not conf.load(v): + print(v + " not found") + exit(1) + loaded = True + +if not loaded: + conf.load_default() + +path=conf.get("private dir") + "/secrets.ldb" +netbios=conf.get("netbios name") + +secrets = ldb.Ldb() +secrets.connect(path) + +search = "(&(objectclass=primaryDomain)(samaccountname=" + \ + netbios + "$))" + +msg = secrets.search(expression=search, attrs=['secret']) + +if not msg: + error = "Error:\n" + error += "Password for host[" + netbios + "] not found in path[" + path + "].\n" + error += "You may want to pass the smb.conf location via the -s option." + print error + exit(1) + +password=msg[0]['secret'][0]; + +print(password) +exit(0) diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6eb47c8595..0119f40c7f 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") @@ -503,6 +504,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, backend_modules = ["normalise", "entryuuid", "paged_searches"] # OpenLDAP handles subtree renames, so we don't want to do any of these things tdb_modules_list = None + elif ldap_backend is not None: + raise "LDAP Backend specified, but LDAP Backend Type not specified" elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: @@ -1043,6 +1046,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 +1085,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 +1383,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 +1399,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/smb_server/smb/nttrans.c b/source4/smb_server/smb/nttrans.c index a959793dde..4a06ea4b91 100644 --- a/source4/smb_server/smb/nttrans.c +++ b/source4/smb_server/smb/nttrans.c @@ -134,6 +134,7 @@ static NTSTATUS nttrans_create(struct smbsrv_request *req, io->ntcreatex.in.security_flags = CVAL(params, 52); io->ntcreatex.in.sec_desc = NULL; io->ntcreatex.in.ea_list = NULL; + io->ntcreatex.in.query_maximal_access = false; req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, params + 53, diff --git a/source4/smb_server/smb/reply.c b/source4/smb_server/smb/reply.c index d7ed052ba0..9c4ee993d2 100644 --- a/source4/smb_server/smb/reply.c +++ b/source4/smb_server/smb/reply.c @@ -2192,6 +2192,7 @@ void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req) io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47); io->ntcreatex.in.ea_list = NULL; io->ntcreatex.in.sec_desc = NULL; + io->ntcreatex.in.query_maximal_access = false; /* we use a couple of bits of the create options internally */ if (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) { 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/smbtorture.c b/source4/torture/smbtorture.c index 37d7d171ca..1329f03b04 100644 --- a/source4/torture/smbtorture.c +++ b/source4/torture/smbtorture.c @@ -540,8 +540,9 @@ int main(int argc,char *argv[]) const char *basedir = NULL; const char *extra_module = NULL; static int list_tests = 0; + int num_extra_users = 0; enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST, - OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS}; + OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,OPT_EXTRA_USER}; struct poptOption long_options[] = { POPT_AUTOHELP @@ -569,6 +570,8 @@ int main(int argc,char *argv[]) "number of simultaneous async requests", NULL}, {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, "set maximum time for smbtorture to live", "seconds"}, + {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER, + "extra user credentials", NULL}, POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS @@ -612,6 +615,15 @@ int main(int argc,char *argv[]) case OPT_SMB_PORTS: lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc)); break; + case OPT_EXTRA_USER: + { + char *option = talloc_asprintf(NULL, "torture:extra_user%u", + ++num_extra_users); + char *value = poptGetOptArg(pc); + lp_set_cmdline(cmdline_lp_ctx, option, value); + talloc_free(option); + } + break; } } |