diff options
48 files changed, 1081 insertions, 642 deletions
diff --git a/source4/auth/sam.c b/source4/auth/sam.c index 9a8045f62d..882196343c 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -157,7 +157,7 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); - acct_expiry = samdb_result_nttime(msg, "accountExpires", 0); + acct_expiry = samdb_result_account_expires(msg, 0); /* Check for when we must change this password, taking the * userAccountControl flags into account */ @@ -351,7 +351,7 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_conte server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0); server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0); - server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0); + server_info->acct_expiry = samdb_result_account_expires(msg, 0); server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0); ncname = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", NULL); diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c index e84f2364d4..fe48f98760 100644 --- a/source4/cluster/ctdb/opendb_ctdb.c +++ b/source4/cluster/ctdb/opendb_ctdb.c @@ -284,6 +284,7 @@ static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { diff --git a/source4/configure.ac b/source4/configure.ac index 5ba441375c..41f1bcf054 100644 --- a/source4/configure.ac +++ b/source4/configure.ac @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. dnl disabled 2.53 requirement - we do work with 2.52 on suse 7.3 for example dnl AC_PREREQ(2.53) -AC_INIT([samba],[],[samba-technical@samba.org]) +AC_INIT([samba],[4],[samba-technical@samba.org]) AC_CONFIG_SRCDIR([include/includes.h]) AC_CONFIG_HEADER(include/config_tmp.h) diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ace5e0edaf..88c8afd6cc 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -434,6 +434,30 @@ NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME def } /* + * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to + * indicate an account doesn't expire. + * + * When Windows initially creates an account, it sets + * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However, + * when changing from an account having a specific expiration date to + * that account never expiring, it sets accountExpires = 0. + * + * Consolidate that logic here to allow clearer logic for account expiry in + * the rest of the code. + */ +NTTIME samdb_result_account_expires(struct ldb_message *msg, + NTTIME default_value) +{ + NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires", + default_value); + + if (ret == (NTTIME)0) + ret = 0x7FFFFFFFFFFFFFFFULL; + + return ret; +} + +/* pull a uint64_t from a result set. */ uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value) @@ -493,7 +517,7 @@ NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); if (maxPwdAge == 0) { - return 0; + return 0x7FFFFFFFFFFFFFFFULL; } else { attr_time -= maxPwdAge; } diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c index 729fd15202..8ceeba9804 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c @@ -30,6 +30,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "lib/util/dlinklist.h" +#include "param/param.h" static int schema_fsmo_init(struct ldb_module *module) { @@ -78,7 +79,7 @@ static int schema_fsmo_init(struct ldb_module *module) } module->private_data = schema_fsmo; - schema = talloc_zero(mem_ctx, struct dsdb_schema); + schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm"))); if (!schema) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 30d0adeda7..c046cb597f 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -29,6 +29,18 @@ #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" +struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience) +{ + struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema); + if (!schema) { + return NULL; + } + + schema->iconv_convenience = iconv_convenience; + return schema; +} + + WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr) { uint32_t i,j; @@ -1150,12 +1162,7 @@ WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf goto nomem; } - schema = talloc_zero(mem_ctx, struct dsdb_schema); - if (!schema) { - goto nomem; - } - - schema->iconv_convenience = lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")); + schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm"))); /* * load the prefixMap attribute from pf diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 9a17e581e3..bc5a45ae2b 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -510,9 +510,8 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, entry_ex->entry.valid_start = NULL; - acct_expiry = samdb_result_nttime(msg, "accountExpires", (NTTIME)-1); - if ((acct_expiry == (NTTIME)-1) || - (acct_expiry == 0x7FFFFFFFFFFFFFFFULL)) { + acct_expiry = samdb_result_account_expires(msg, 0); + if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) { entry_ex->entry.valid_end = NULL; } else { entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end)); diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index a99cf6ded8..66f36af870 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -276,9 +276,28 @@ krb5_error_code samba_kdc_check_client_access(void *priv, /* TODO: Need a more complete mapping of NTSTATUS to krb5kdc errors */ - if (!NT_STATUS_IS_OK(nt_status)) { + /* TODO: Also need to add the appropriate e-data struct of type + * PA-PW-SALT (3) that includes the NT_STATUS code, which gives Windows + * the information it needs to display the appropriate dialog. */ + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) + return KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) + return KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) + return KRB5KDC_ERR_POLICY; + else if (!NT_STATUS_IS_OK(nt_status)) { return KRB5KDC_ERR_POLICY; } + return 0; } diff --git a/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif b/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif index 997b801d84..472ab48fac 100644 --- a/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif +++ b/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif @@ -46,7 +46,7 @@ pwdLastSet: 0 primaryGroupID: 513 objectSid: S-1-5-21-43662522-77495566-38969261-500 adminCount: 1 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 sAMAccountName: Administrator sAMAccountType: 0x30000000 diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c index 63049b06fc..71ba37b479 100644 --- a/source4/lib/ldb_wrap.c +++ b/source4/lib/ldb_wrap.c @@ -63,7 +63,7 @@ static void ldb_wrap_debug(void *context, enum ldb_debug_level level, }; vasprintf(&s, fmt, ap); if (!s) return; - DEBUG(level, ("ldb: %s\n", s)); + DEBUG(samba_level, ("ldb: %s\n", s)); free(s); } diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c index ec2ada53ff..6c16935f21 100644 --- a/source4/libcli/raw/rawnegotiate.c +++ b/source4/libcli/raw/rawnegotiate.c @@ -187,6 +187,10 @@ NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) transport->negotiate.capabilities &= ~CAP_STATUS32; } + if (!transport->options.use_level2_oplocks) { + transport->negotiate.capabilities &= ~CAP_LEVEL_II_OPLOCKS; + } + failed: return smbcli_request_destroy(req); } diff --git a/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index efd4aa860f..3505fc895c 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/librpc/idl/krb5pac.idl @@ -31,6 +31,19 @@ interface krb5pac samr_RidWithAttributeArray res_groups; } PAC_LOGON_INFO; + typedef struct { + [value(2*strlen_m(upn_name))] uint16 upn_size; + uint16 upn_offset; + [value(2*strlen_m(domain_name))] uint16 domain_size; + uint16 domain_offset; + uint16 unknown3; /* 0x01 */ + uint16 unknown4; + uint32 unknown5; + [charset(UTF16)] uint8 upn_name[upn_size+2]; + [charset(UTF16)] uint8 domain_name[domain_size+2]; + uint32 unknown6; /* padding */ + } PAC_UNKNOWN_12; + typedef [public] struct { [value(0x00081001)] uint32 unknown1; [value(0xCCCCCCCC)] uint32 unknown2; @@ -44,14 +57,21 @@ interface krb5pac PAC_TYPE_SRV_CHECKSUM = 6, PAC_TYPE_KDC_CHECKSUM = 7, PAC_TYPE_LOGON_NAME = 10, - PAC_TYPE_CONSTRAINED_DELEGATION = 11 + PAC_TYPE_CONSTRAINED_DELEGATION = 11, + PAC_TYPE_UNKNOWN_12 = 12 } PAC_TYPE; + typedef struct { + [flag(NDR_REMAINING)] DATA_BLOB remaining; + } DATA_BLOB_REM; + typedef [public,nodiscriminant,gensize] union { [case(PAC_TYPE_LOGON_INFO)] PAC_LOGON_INFO_CTR logon_info; [case(PAC_TYPE_SRV_CHECKSUM)] PAC_SIGNATURE_DATA srv_cksum; [case(PAC_TYPE_KDC_CHECKSUM)] PAC_SIGNATURE_DATA kdc_cksum; [case(PAC_TYPE_LOGON_NAME)] PAC_LOGON_NAME logon_name; + [case(PAC_TYPE_UNKNOWN_12)] [subcontext(0)] DATA_BLOB_REM unknown; + /* [case(PAC_TYPE_UNKNOWN_12)] PAC_UNKNOWN_12 unknown; */ } PAC_INFO; typedef [public,nopush,nopull,noprint] struct { @@ -67,10 +87,6 @@ interface krb5pac PAC_BUFFER buffers[num_buffers]; } PAC_DATA; - typedef struct { - [flag(NDR_REMAINING)] DATA_BLOB remaining; - } DATA_BLOB_REM; - typedef [public] struct { PAC_TYPE type; uint32 ndr_size; diff --git a/source4/librpc/idl/opendb.idl b/source4/librpc/idl/opendb.idl index eaa626e89d..e3bc2d0f17 100644 --- a/source4/librpc/idl/opendb.idl +++ b/source4/librpc/idl/opendb.idl @@ -23,6 +23,7 @@ interface opendb /* we need a per-entry delete on close, as well as a per-file one, to cope with strange semantics on open */ boolean8 delete_on_close; + boolean8 allow_level_II_oplock; uint32 oplock_level; } opendb_entry; diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 6c1a9c070a..a7e5458aaf 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -98,11 +98,13 @@ _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { return ops->odb_open_file(lck, file_handle, path, stream_id, share_access, access_mask, delete_on_close, open_disposition, - break_to_none, oplock_level, oplock_granted); + break_to_none, allow_level_II_oplock, + oplock_level, oplock_granted); } diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 69a7f718ba..1c7f815dea 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -30,6 +30,7 @@ struct opendb_ops { uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted); NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle, diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index 47b35f594c..0736af3d1e 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -344,7 +344,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, break request and suspending this call until the break is acknowledged or the file is closed */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -391,7 +392,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, * send an oplock break to the holder of the * oplock and tell caller to retry later */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -418,6 +420,7 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { struct odb_context *odb = lck->odb; @@ -447,13 +450,14 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, NT_STATUS_NOT_OK_RETURN(status); /* see if it conflicts */ - e.server = odb->ntvfs_ctx->server_id; - e.file_handle = file_handle; - e.stream_id = stream_id; - e.share_access = share_access; - e.access_mask = access_mask; - e.delete_on_close = delete_on_close; - e.oplock_level = OPLOCK_NONE; + e.server = odb->ntvfs_ctx->server_id; + e.file_handle = file_handle; + e.stream_id = stream_id; + e.share_access = share_access; + e.access_mask = access_mask; + e.delete_on_close = delete_on_close; + e.allow_level_II_oplock = allow_level_II_oplock; + e.oplock_level = OPLOCK_NONE; /* possibly grant an exclusive, batch or level2 oplock @@ -466,17 +470,23 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, if (file.num_entries == 0) { e.oplock_level = OPLOCK_EXCLUSIVE; *oplock_granted = EXCLUSIVE_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_BATCH) { if (file.num_entries == 0) { e.oplock_level = OPLOCK_BATCH; *oplock_granted = BATCH_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_LEVEL_II) { e.oplock_level = OPLOCK_LEVEL_II; diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index a708dbff51..7a2edc7e2c 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -181,6 +181,14 @@ struct ntvfs_context { enum protocol_types protocol; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + */ +#define NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS 0x0000000000000001LLU + uint64_t client_caps; + /* * linked list of module contexts */ @@ -257,6 +265,14 @@ struct ntvfs_request { /* the smb pid is needed for locking contexts */ uint16_t smbpid; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + * see NTVFS_CLIENT_CAP_* + */ + uint64_t client_caps; + /* some statictics for the management tools */ struct { /* the system time when the request arrived */ diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index f5a24f23a0..35becabcf9 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -153,6 +153,7 @@ _PUBLIC_ bool ntvfs_interface_differs(const struct ntvfs_critical_sizes *const i */ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, enum ntvfs_type type, enum protocol_types protocol, + uint64_t ntvfs_client_caps, struct event_context *ev, struct messaging_context *msg, struct loadparm_context *lp_ctx, struct server_id server_id, struct ntvfs_context **_ctx) @@ -168,6 +169,7 @@ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, e ctx = talloc_zero(mem_ctx, struct ntvfs_context); NT_STATUS_HAVE_NO_MEMORY(ctx); ctx->protocol = protocol; + ctx->client_caps = ntvfs_client_caps; ctx->type = type; ctx->config = talloc_steal(ctx, scfg); ctx->event_ctx = ev; diff --git a/source4/ntvfs/ntvfs_util.c b/source4/ntvfs/ntvfs_util.c index 7432ac2c13..ebe8008edd 100644 --- a/source4/ntvfs/ntvfs_util.c +++ b/source4/ntvfs/ntvfs_util.c @@ -42,6 +42,7 @@ _PUBLIC_ struct ntvfs_request *ntvfs_request_create(struct ntvfs_context *ctx, T req->async_states = NULL; req->session_info = session_info; req->smbpid = smbpid; + req->client_caps = ctx->client_caps; req->statistics.request_time = request_time; async = talloc(req, struct ntvfs_async_state); diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index adf4c1ac18..47b44b9634 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -293,7 +293,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); @@ -347,7 +347,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; @@ -544,6 +544,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, bool del_on_close; struct pvfs_filename *parent; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { @@ -658,10 +659,15 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + oplock_level, &oplock_granted); talloc_free(lck); if (!NT_STATUS_IS_OK(status)) { /* bad news, we must have hit a race - we don't delete the file @@ -696,21 +702,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, DLIST_ADD(pvfs->files.list, f); + /* setup a destructor to avoid file descriptor leaks on + abnormal termination */ + talloc_set_destructor(f, pvfs_fnum_destructor); + talloc_set_destructor(f->handle, pvfs_handle_destructor); + if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) { oplock_granted = OPLOCK_BATCH; } else if (oplock_granted != OPLOCK_NONE) { status = pvfs_setup_oplock(f, oplock_granted); if (!NT_STATUS_IS_OK(status)) { - talloc_free(lck); return status; } } - /* setup a destructor to avoid file descriptor leaks on - abnormal termination */ - talloc_set_destructor(f, pvfs_fnum_destructor); - talloc_set_destructor(f->handle, pvfs_handle_destructor); - io->generic.out.oplock_level = oplock_granted; io->generic.out.file.ntvfs = f->ntvfs; io->generic.out.create_action = NTCREATEX_ACTION_CREATED; @@ -1048,6 +1053,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, bool del_on_close; bool stream_existed, stream_truncate=false; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; /* use the generic mapping code to avoid implementing all the different open calls. */ @@ -1242,11 +1248,16 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + /* see if we are allowed to open at the same time as existing opens */ status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + oplock_level, &oplock_granted); /* * on a sharing violation we need to retry when the file is closed by diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index cf30ddbc59..dfa3697af7 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -22,6 +22,7 @@ #include "includes.h" #include "lib/messaging/messaging.h" #include "lib/messaging/irpc.h" +#include "system/time.h" #include "vfs_posix.h" @@ -29,9 +30,63 @@ struct pvfs_oplock { struct pvfs_file_handle *handle; struct pvfs_file *file; uint32_t level; + struct timeval break_to_level_II; + struct timeval break_to_none; struct messaging_context *msg_ctx; }; +static NTSTATUS pvfs_oplock_release_internal(struct pvfs_file_handle *h, + uint8_t oplock_break) +{ + struct odb_lock *olck; + NTSTATUS status; + + if (h->fd == -1) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + if (!h->have_opendb_entry) { + return NT_STATUS_FOOBAR; + } + + if (!h->oplock) { + return NT_STATUS_FOOBAR; + } + + olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); + if (olck == NULL) { + DEBUG(0,("Unable to lock opendb for oplock update\n")); + return NT_STATUS_FOOBAR; + } + + if (oplock_break == OPLOCK_BREAK_TO_NONE) { + h->oplock->level = OPLOCK_NONE; + } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { + h->oplock->level = OPLOCK_LEVEL_II; + } else { + /* fallback to level II in case of a invalid value */ + DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); + h->oplock->level = OPLOCK_LEVEL_II; + } + status = odb_update_oplock(olck, h, h->oplock->level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update oplock level for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + talloc_free(olck); + return status; + } + + talloc_free(olck); + + /* after a break to none, we no longer have an oplock attached */ + if (h->oplock->level == OPLOCK_NONE) { + talloc_free(h->oplock); + h->oplock = NULL; + } + + return NT_STATUS_OK; +} + /* receive oplock breaks and forward them to the client */ @@ -41,13 +96,65 @@ static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level) struct pvfs_file *f = opl->file; struct pvfs_file_handle *h = opl->handle; struct pvfs_state *pvfs = h->pvfs; + struct timeval cur = timeval_current(); + struct timeval *last = NULL; + struct timeval end; + + switch (level) { + case OPLOCK_BREAK_TO_LEVEL_II: + last = &opl->break_to_level_II; + break; + case OPLOCK_BREAK_TO_NONE: + last = &opl->break_to_none; + break; + } + + if (!last) { + DEBUG(0,("%s: got unexpected level[0x%02X]\n", + __FUNCTION__, level)); + return; + } + + if (timeval_is_zero(last)) { + /* + * this is the first break we for this level + * remember the time + */ + *last = cur; - DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n", - level, h->name->original_name, h)); - status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + DEBUG(0,("%s: sending oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("%s: sending oplock break failed: %s\n", + __FUNCTION__, nt_errstr(status))); + } + return; + } + + end = timeval_add(last, pvfs->oplock_break_timeout, 0); + + if (timeval_compare(&cur, &end) < 0) { + /* + * If it's not expired just ignore the break + * as we already sent the break request to the client + */ + DEBUG(0,("%s: do not resend oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + return; + } + + /* + * If the client did not send a release within the + * oplock break timeout time frame we auto release + * the oplock + */ + DEBUG(0,("%s: auto release oplock level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = pvfs_oplock_release_internal(h, level); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n", - nt_errstr(status))); + DEBUG(0,("%s: failed to auto release the oplock[0x%02X]: %s\n", + __FUNCTION__, level, nt_errstr(status))); } } @@ -113,7 +220,7 @@ NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted) return NT_STATUS_OK; } - opl = talloc(f->handle, struct pvfs_oplock); + opl = talloc_zero(f->handle, struct pvfs_oplock); NT_STATUS_HAVE_NO_MEMORY(opl); opl->handle = f->handle; @@ -140,8 +247,6 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; - struct pvfs_file_handle *h; - struct odb_lock *olck; uint8_t oplock_break; NTSTATUS status; @@ -150,52 +255,15 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - h = f->handle; - - if (h->fd == -1) { - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - - if (!h->have_opendb_entry) { - return NT_STATUS_FOOBAR; - } - - if (!h->oplock) { - return NT_STATUS_FOOBAR; - } - - olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); - if (olck == NULL) { - DEBUG(0,("Unable to lock opendb for oplock update\n")); - return NT_STATUS_FOOBAR; - } - oplock_break = (lck->lockx.in.mode >> 8) & 0xFF; - if (oplock_break == OPLOCK_BREAK_TO_NONE) { - h->oplock->level = OPLOCK_NONE; - } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { - h->oplock->level = OPLOCK_LEVEL_II; - } else { - /* fallback to level II in case of a invalid value */ - DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); - h->oplock->level = OPLOCK_LEVEL_II; - } - status = odb_update_oplock(olck, h, h->oplock->level); + + status = pvfs_oplock_release_internal(f->handle, oplock_break); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); + DEBUG(0,("%s: failed to release the oplock[0x%02X]: %s\n", + __FUNCTION__, oplock_break, nt_errstr(status))); return status; } - talloc_free(olck); - - /* after a break to none, we no longer have an oplock attached */ - if (h->oplock->level == OPLOCK_NONE) { - talloc_free(h->oplock); - h->oplock = NULL; - } - return NT_STATUS_OK; } @@ -205,7 +273,7 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) struct odb_lock *olck; NTSTATUS status; - if (h->oplock && h->oplock->level == OPLOCK_EXCLUSIVE) { + if (h->oplock && h->oplock->level != OPLOCK_LEVEL_II) { return NT_STATUS_OK; } @@ -215,16 +283,6 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) return NT_STATUS_FOOBAR; } - if (h->oplock && h->oplock->level == OPLOCK_BATCH) { - status = odb_update_oplock(olck, h, OPLOCK_LEVEL_II); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); - return status; - } - } - status = odb_break_oplocks(olck); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to break level2 oplocks to none for '%s' - %s\n", diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index d94ab92ac9..a1d29b0771 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -316,7 +316,9 @@ static const struct enum_list enum_smb_signing_vals[] = { static const struct enum_list enum_server_role[] = { {ROLE_STANDALONE, "standalone"}, {ROLE_DOMAIN_MEMBER, "member server"}, + {ROLE_DOMAIN_MEMBER, "member"}, {ROLE_DOMAIN_CONTROLLER, "domain controller"}, + {ROLE_DOMAIN_CONTROLLER, "dc"}, {-1, NULL} }; @@ -2614,6 +2616,6 @@ void lp_smbcli_options(struct loadparm_context *lp_ctx, options->ntstatus_support = lp_nt_status_support(lp_ctx); options->max_protocol = lp_cli_maxprotocol(lp_ctx); options->unicode = lp_unicode(lp_ctx); - options->use_oplocks = false; - options->use_level2_oplocks = false; + options->use_oplocks = true; + options->use_level2_oplocks = true; } diff --git a/source4/rpc_server/srvsvc/srvsvc_ntvfs.c b/source4/rpc_server/srvsvc/srvsvc_ntvfs.c index ccd6c4f74e..43fb24c0c3 100644 --- a/source4/rpc_server/srvsvc/srvsvc_ntvfs.c +++ b/source4/rpc_server/srvsvc/srvsvc_ntvfs.c @@ -98,6 +98,7 @@ NTSTATUS srvsvc_create_ntvfs_context(struct dcesrv_call_state *dce_call, /* init ntvfs function pointers */ status = ntvfs_init_connection(c, scfg, type, PROTOCOL_NT1, + 0,/* ntvfs_client_caps */ dce_call->event_ctx, dce_call->conn->msg_ctx, dce_call->conn->dce_ctx->lp_ctx, diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail index 66565ca6fc..496af316ec 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -33,4 +33,3 @@ rpc.netlogon.*.GetTrustPasswords base.charset.*.Testing partial surrogate .*net.api.delshare.* # DelShare isn't implemented yet rap.*netservergetinfo -local.torture.provision diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 8d5f4250c9..e91b320c07 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -147,7 +147,12 @@ class Ldb(ldb.Ldb): k = 0 while ++k < 10 and (previous_remaining != current_remaining): # and the rest - res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + try: + res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + return + previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ea2feb981b..ebca1f8e40 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -32,6 +32,7 @@ from socket import gethostname, gethostbyname import param import registry import samba +from auth import system_session from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB import security @@ -65,7 +66,14 @@ class ProvisionPaths: self.dns_keytab = None self.dns = None self.winsdb = None + self.private_dir = None +class ProvisionResult: + def __init__(self): + self.paths = None + self.domaindn = None + self.lp = None + self.samdb = None def check_install(lp, session_info, credentials): """Check whether the current install seems ok. @@ -197,20 +205,20 @@ def provision_paths_from_lp(lp, dnsdomain): :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() - private_dir = lp.get("private dir") + paths.private_dir = lp.get("private dir") paths.keytab = "secrets.keytab" paths.dns_keytab = "dns.keytab" - paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") - paths.idmapdb = os.path.join(private_dir, lp.get("idmap database") or "idmap.ldb") - paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") - paths.templates = os.path.join(private_dir, "templates.ldb") - paths.dns = os.path.join(private_dir, dnsdomain + ".zone") - paths.winsdb = os.path.join(private_dir, "wins.ldb") - paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") - paths.smbconf = os.path.join(private_dir, "smb.conf") - paths.phpldapadminconfig = os.path.join(private_dir, + paths.shareconf = os.path.join(paths.private_dir, "share.ldb") + paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") + paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb") + paths.templates = os.path.join(paths.private_dir, "templates.ldb") + paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") + paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") + paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") + paths.smbconf = os.path.join(paths.private_dir, "smb.conf") + paths.phpldapadminconfig = os.path.join(paths.private_dir, "phpldapadmin-config.php") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" @@ -341,12 +349,21 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid", "paged_searches"] + # We can handle linked attributes here, as we don't have directory-side subtree operations + tdb_modules_list = ["linked_attributes"] elif ldap_backend_type == "openldap": 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 serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: backend_modules = ["objectguid"] + + if tdb_modules_list is None: + tdb_modules_list_as_string = "" + else: + tdb_modules_list_as_string = ","+",".join(tdb_modules_list) samdb.transaction_start() try: @@ -362,7 +379,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "CONFIGDN_MOD": "naming_fsmo,instancetype", "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", "MODULES_LIST": ",".join(modules_list), - "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "TDB_MODULES_LIST": tdb_modules_list_as_string, "MODULES_LIST2": ",".join(modules_list2), "BACKEND_MOD": ",".join(backend_modules), }) @@ -561,9 +578,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, :note: This will wipe the main SAM database file! """ - assert serverrole in ("domain controller", "member server") - - erase = (fill != FILL_DRS) + erase = (fill != FILL_DRS) # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, @@ -588,7 +603,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": samdb.set_invocation_id(invocationid) load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename) @@ -699,7 +714,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "KRBTGTPASS_B64": b64encode(krbtgtpass), }) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": message("Setting up self join") setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn, invocationid=invocationid, @@ -725,13 +740,14 @@ FILL_FULL = "FULL" FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" -def provision(lp, setup_dir, message, paths, session_info, - credentials, samdb_fill=FILL_FULL, realm=None, rootdn=None, +def provision(setup_dir, message, session_info, + credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, hostip=None, domainsid=None, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + wheel=None, backup=None, aci=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 @@ -768,41 +784,103 @@ def provision(lp, setup_dir, message, paths, session_info, backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] if aci is None: aci = "# no aci for local ldb" + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if hostip is None: + hostip = gethostbyname(hostname) + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + if targetdir is not None: + if not os.path.exists(targetdir): + os.mkdir(targetdir) + if not os.path.exists(os.path.join(targetdir, "etc")): + os.mkdir(os.path.join(targetdir, "etc")) + + smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) + + # only install a new smb.conf if there isn't one there already + + if not os.path.exists(smbconf): + message("Setting up smb.conf") + if serverrole is None: + serverrole = "standalone" + + assert serverrole in ("domain controller", "member server", "standalone") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" + + assert domain is not None + assert realm is not None + + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) + + default_lp.set("lock dir", os.path.abspath(targetdir)) + + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(os.path.join(sysvol, "scripts")) + + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN": domain, + "REALM": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) + + lp = param.LoadParm() + lp.load(smbconf) + if serverrole is None: serverrole = lp.get("server role") - assert serverrole in ("domain controller", "member server") + assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": invocationid = uuid.random() if realm is None: realm = lp.get("realm") + assert realm is not None + realm = realm.upper() + if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % - (lp.get("realm"), realm)) + raise Exception("realm '%s' in %s must match chosen realm '%s'" % + (lp.get("realm"), smbconf, realm)) + + dnsdomain = realm.lower() + + paths = provision_paths_from_lp(lp, dnsdomain) + + if targetdir is not None: + if not os.path.exists(paths.private_dir): + os.mkdir(paths.private_dir) ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") if ldap_backend == "ldapi": # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") - - assert realm is not None - realm = realm.upper() - - if hostname is None: - hostname = gethostname().split(".")[0].lower() + ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - if hostip is None: - hostip = gethostbyname(hostname) - - netbiosname = hostname.upper() - if not valid_netbios_name(netbiosname): - raise InvalidNetbiosName(netbiosname) - - dnsdomain = realm.lower() if serverrole == "domain controller": - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if domaindn is None: + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if domain is None: domain = lp.get("workgroup") @@ -815,39 +893,22 @@ def provision(lp, setup_dir, message, paths, session_info, if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) else: - domaindn = "CN=" + netbiosname + if domaindn is None: + domaindn = "CN=" + netbiosname domain = netbiosname if rootdn is None: rootdn = domaindn - configdn = "CN=Configuration," + rootdn - schemadn = "CN=Schema," + configdn + if configdn is None: + configdn = "CN=Configuration," + rootdn + if schemadn is None: + schemadn = "CN=Schema," + configdn message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) - assert paths.smbconf is not None - - # only install a new smb.conf if there isn't one there already - if not os.path.exists(paths.smbconf): - message("Setting up smb.conf") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member server": - smbconfsuffix = "member" - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), - paths.smbconf, { - "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": paths.netlogon, - "SYSVOLPATH": paths.sysvol, - }) - lp.load(paths.smbconf) - # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") @@ -911,32 +972,57 @@ def provision(lp, setup_dir, message, paths, session_info, message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) + # Only make a zone file on the first DC, it should be replicated with DNS replication + if serverrole == "domain controller": + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) + + message("Setting up DNS zone: %s" % dnsdomain) + create_zone_file(paths.dns, setup_path, samdb, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm, + domainguid=domainguid, hostguid=hostguid) + message("Please install the zone located in %s into your DNS server" % paths.dns) + message("Setting up phpLDAPadmin configuration") create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - if lp.get("server role") == "domain controller": - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) - - domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") - assert isinstance(domainguid, str) - hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", - expression="(&(objectClass=computer)(cn=%s))" % hostname, - scope=SCOPE_SUBTREE) - assert isinstance(hostguid, str) - - message("Setting up DNS zone: %s" % dnsdomain) - create_zone_file(paths.dns, setup_path, samdb, - hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm, - domainguid=domainguid, hostguid=hostguid) - message("Please install the zone located in %s into your DNS server" % paths.dns) - - return domaindn - + result = ProvisionResult() + result.domaindn = domaindn + result.paths = paths + result.lp = lp + result.samdb = samdb + return result + +def provision_become_dc(setup_dir=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + domain=None, hostname=None, domainsid=None, + hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, + ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): + + def message(text): + """print a message if quiet is not set.""" + print text + + provision(setup_dir, message, system_session(), None, + smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, + rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, + domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); + def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. @@ -978,7 +1064,6 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, "HOSTGUID": hostguid, }) - def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 01b62ff984..f40f2cffe7 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -207,7 +207,7 @@ def import_wins(samba4_winsdb, samba3_winsdb): "objectClass": "winsMaxVersion", "maxVersion": str(version_id)}) -def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, paths): +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir): oldconf = samba3.get_conf() if oldconf.get("domain logons") == "True": @@ -218,11 +218,9 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: serverrole = "member server" - lp.set("server role", serverrole) domainname = oldconf.get("workgroup") if domainname: domainname = str(domainname) - lp.set("workgroup", domainname) realm = oldconf.get("realm") netbiosname = oldconf.get("netbios name") @@ -235,7 +233,6 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, if realm is None: realm = domainname.lower() message("No realm specified in smb.conf file, assuming '%s'\n" % realm) - lp.set("realm", realm) domainguid = secrets_db.get_domain_guid(domainname) domainsid = secrets_db.get_sid(domainname) @@ -247,15 +244,13 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, - samdb_fill=FILL_DRS, paths=paths, session_info=session_info, - credentials=credentials, realm=realm, - domain=domainname, domainsid=domainsid, domainguid=domainguid, - machinepass=machinepass, serverrole=serverrole) + result = provision(setup_dir=setup_dir, message=message, + samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info, + credentials=credentials, realm=realm, + domain=domainname, domainsid=domainsid, domainguid=domainguid, + machinepass=machinepass, serverrole=serverrole, targetdir=targetdir) - samdb = SamDB(paths.samdb, credentials=credentials, lp=lp, session_info=session_info) - - import_wins(Ldb(paths.winsdb), samba3.get_wins_db()) + import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) # FIXME: import_registry(registry.Registry(), samba3.get_registry()) @@ -271,12 +266,12 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, passdb = samba3.get_sam_db() for name in passdb: user = passdb[name] - #FIXME: import_sam_account(samdb, user, domaindn, domainsid) + #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid) if hasattr(passdb, 'ldap_url'): message("Enabling Samba3 LDAP mappings for SAM database") - enable_samba3sam(samdb, passdb.ldap_url) + enable_samba3sam(result.samdb, passdb.ldap_url) def enable_samba3sam(samdb, ldapurl): diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh index bea4173555..8102095958 100755 --- a/source4/selftest/samba4_tests.sh +++ b/source4/selftest/samba4_tests.sh @@ -217,7 +217,7 @@ done plantest "rpc.echo on ncacn_np over smb2" dc $smb4torture ncacn_np:"\$SERVER[smb2]" -U"\$USERNAME"%"\$PASSWORD" -W \$DOMAIN RPC-ECHO "$*" # Tests against the NTVFS POSIX backend -NTVFSARGS="--option=torture:sharedelay=100000" +NTVFSARGS="--option=torture:sharedelay=100000 --option=torture:oplocktimeout=3" smb2=`$smb4torture --list | grep "^SMB2-" | xargs` raw=`$smb4torture --list | grep "^RAW-" | xargs` base=`$smb4torture --list | grep "^BASE-" | xargs` diff --git a/source4/setup/provision b/source4/setup/provision index 033d2491f2..629bfa10e0 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -30,9 +30,7 @@ import samba from auth import system_session import samba.getopt as options -import param from samba.provision import (provision, - provision_paths_from_lp, FILL_FULL, FILL_NT4SYNC, FILL_DRS) @@ -90,7 +88,7 @@ parser.add_option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TY parser.add_option("--aci", type="string", metavar="ACI", help="An arbitary LDIF fragment, particularly useful to loading a backend ACI value into a target LDAP server. You must provide at least a realm and domain") parser.add_option("--server-role", type="choice", metavar="ROLE", - choices=["domain controller", "member server"], + choices=["domain controller", "dc", "member server", "member", "standalone"], help="Set server role to provision for (default standalone)") parser.add_option("--partitions-only", help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true") @@ -112,27 +110,17 @@ if opts.realm is None or opts.domain is None: parser.print_usage() sys.exit(1) -# cope with an initially blank smb.conf -private_dir = None -lp = sambaopts.get_loadparm() -if opts.targetdir is not None: - if not os.path.exists(opts.targetdir): - os.mkdir(opts.targetdir) - private_dir = os.path.join(opts.targetdir, "private") - if not os.path.exists(private_dir): - os.mkdir(private_dir) - lp.set("private dir", os.path.abspath(private_dir)) - lp.set("lock dir", os.path.abspath(opts.targetdir)) -lp.set("realm", opts.realm) -lp.set("workgroup", opts.domain) -lp.set("server role", opts.server_role or "domain controller") +smbconf = sambaopts.get_loadparm_path() if opts.aci is not None: print "set ACI: %s" % opts.aci -paths = provision_paths_from_lp(lp, opts.realm.lower()) -if sambaopts.get_loadparm_path() is not None: - paths.smbconf = sambaopts.get_loadparm_path() +if opts.server_role == "dc": + server_role = "domain controller" +elif opts.server_role == "member": + server_role = "member server" +else: + server_role = opts.server_role creds = credopts.get_credentials() @@ -146,9 +134,9 @@ if opts.blank: elif opts.partitions_only: samdb_fill = FILL_DRS -provision(lp, setup_dir, message, paths, - system_session(), creds, - samdb_fill=samdb_fill, realm=opts.realm, +provision(setup_dir, message, + system_session(), creds, smbconf=smbconf, targetdir=opts.targetdir, + samdb_fill=samdb_fill, realm=opts.realm, domain=opts.domain, domainguid=opts.domain_guid, domainsid=opts.domain_sid, policyguid=opts.policy_guid, hostname=opts.host_name, hostip=opts.host_ip, hostguid=opts.host_guid, @@ -156,7 +144,7 @@ provision(lp, setup_dir, message, paths, krbtgtpass=opts.krbtgtpass, machinepass=opts.machinepass, dnspass=opts.dnspass, root=opts.root, nobody=opts.nobody, nogroup=opts.nogroup, wheel=opts.wheel, users=opts.users, - aci=opts.aci, serverrole=opts.server_role, + aci=opts.aci, serverrole=server_role, ldap_backend=opts.ldap_backend, ldap_backend_type=opts.ldap_backend_type) diff --git a/source4/setup/provision.smb.conf.dc b/source4/setup/provision.smb.conf.dc index 5b8e141cbf..ad06be4301 100644 --- a/source4/setup/provision.smb.conf.dc +++ b/source4/setup/provision.smb.conf.dc @@ -1,8 +1,10 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} [netlogon] path = ${NETLOGONPATH} diff --git a/source4/setup/provision.smb.conf.member b/source4/setup/provision.smb.conf.member index bc37d4f3d3..0d742fb903 100644 --- a/source4/setup/provision.smb.conf.member +++ b/source4/setup/provision.smb.conf.member @@ -1,5 +1,7 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} diff --git a/source4/setup/provision.smb.conf.standalone b/source4/setup/provision.smb.conf.standalone index bc37d4f3d3..0d742fb903 100644 --- a/source4/setup/provision.smb.conf.standalone +++ b/source4/setup/provision.smb.conf.standalone @@ -1,5 +1,7 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} diff --git a/source4/setup/provision_templates.ldif b/source4/setup/provision_templates.ldif index cc0ab212cd..8f4ed08252 100644 --- a/source4/setup/provision_templates.ldif +++ b/source4/setup/provision_templates.ldif @@ -27,7 +27,7 @@ lastLogoff: 0 lastLogon: 0 pwdLastSet: 0 primaryGroupID: 513 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 dn: CN=TemplateTrustingDomain,CN=Templates @@ -39,7 +39,7 @@ badPasswordTime: 0 lastLogoff: 0 lastLogon: 0 primaryGroupID: 513 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 dn: CN=TemplateGroup,CN=Templates diff --git a/source4/setup/provision_users.ldif b/source4/setup/provision_users.ldif index 4b053d9166..5a24e07492 100644 --- a/source4/setup/provision_users.ldif +++ b/source4/setup/provision_users.ldif @@ -5,7 +5,7 @@ description: Built-in account for administering the computer/domain userAccountControl: 66048 objectSid: ${DOMAINSID}-500 adminCount: 1 -accountExpires: -1 +accountExpires: 9223372036854775807 sAMAccountName: Administrator isCriticalSystemObject: TRUE sambaPassword:: ${ADMINPASS_B64} diff --git a/source4/setup/tests/blackbox_provision.sh b/source4/setup/tests/blackbox_provision.sh index 0aed7bb8b7..83c045e40d 100755 --- a/source4/setup/tests/blackbox_provision.sh +++ b/source4/setup/tests/blackbox_provision.sh @@ -27,7 +27,10 @@ testit() { return $status } -testit "simple" $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple +testit "simple-default" $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-default +testit "simple-dc" $PYTHON ./setup/provision $CONFIGURATION --server-role="dc" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-dc +testit "simple-member" $PYTHON ./setup/provision $CONFIGURATION --server-role="member" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-member +testit "simple-standalone" $PYTHON ./setup/provision $CONFIGURATION --server-role="standalone" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-standalone reprovision() { $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir="$PREFIX/reprovision" diff --git a/source4/setup/upgrade.py b/source4/setup/upgrade.py index 960cd1b9e2..569b179544 100755 --- a/source4/setup/upgrade.py +++ b/source4/setup/upgrade.py @@ -50,7 +50,6 @@ else: samba3 = Samba3(libdir, smbconf) from samba.upgrade import upgrade_provision -from samba.provision import provision_paths_from_lp message("Provisioning\n") @@ -59,13 +58,6 @@ if setup_dir is None: setup_dir = "setup" creds = credopts.get_credentials() -lp = sambaopts.get_loadparm() -if opts.targetdir is not None: - if not os.path.exists(opts.targetdir): - os.mkdir(opts.targetdir) - lp.set("private dir", os.path.abspath(opts.targetdir)) - lp.set("lock dir", os.path.abspath(opts.targetdir)) -paths = provision_paths_from_lp(lp, "") -paths.smbconf = sambaopts.get_loadparm_path() + upgrade_provision(samba3, setup_dir, message, credentials=creds, session_info=system_session(), - lp=lp, paths=paths) + smbconf=sambaopts.get_loadparm_path(), targetdir=opts.targetdir) diff --git a/source4/smb_server/smb/nttrans.c b/source4/smb_server/smb/nttrans.c index f6edc407d6..a20c41ba4d 100644 --- a/source4/smb_server/smb/nttrans.c +++ b/source4/smb_server/smb/nttrans.c @@ -460,7 +460,7 @@ static NTSTATUS nttrans_backend(struct smbsrv_request *req, static void reply_nttrans_send(struct ntvfs_request *ntvfs) { struct smbsrv_request *req; - uint16_t params_left, data_left; + uint32_t params_left, data_left; uint8_t *params, *data; struct smb_nttrans *trans; struct nttrans_op *op; @@ -502,7 +502,7 @@ static void reply_nttrans_send(struct ntvfs_request *ntvfs) /* we need to divide up the reply into chunks that fit into the negotiated buffer size */ do { - uint16_t this_data, this_param, max_bytes; + uint32_t this_data, this_param, max_bytes; uint_t align1 = 1, align2 = (params_left ? 2 : 0); struct smbsrv_request *this_req; @@ -573,9 +573,9 @@ void smbsrv_reply_nttrans(struct smbsrv_request *req) { struct nttrans_op *op; struct smb_nttrans *trans; - uint16_t param_ofs, data_ofs; - uint16_t param_count, data_count; - uint16_t param_total, data_total; + uint32_t param_ofs, data_ofs; + uint32_t param_count, data_count; + uint32_t param_total, data_total; /* parse request */ if (req->in.wct < 19) { diff --git a/source4/smb_server/smb/service.c b/source4/smb_server/smb/service.c index 35b3653026..52471c09c9 100644 --- a/source4/smb_server/smb/service.c +++ b/source4/smb_server/smb/service.c @@ -36,6 +36,7 @@ static NTSTATUS make_connection_scfg(struct smbsrv_request *req, { struct smbsrv_tcon *tcon; NTSTATUS status; + uint64_t ntvfs_caps = 0; tcon = smbsrv_smb_tcon_new(req->smb_conn, scfg->name); if (!tcon) { @@ -44,9 +45,14 @@ static NTSTATUS make_connection_scfg(struct smbsrv_request *req, } req->tcon = tcon; + if (req->smb_conn->negotiate.client_caps & CAP_LEVEL_II_OPLOCKS) { + ntvfs_caps |= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; + } + /* init ntvfs function pointers */ status = ntvfs_init_connection(tcon, scfg, type, req->smb_conn->negotiate.protocol, + ntvfs_caps, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, diff --git a/source4/smb_server/smb2/tcon.c b/source4/smb_server/smb2/tcon.c index 7f7d558b16..040947f84f 100644 --- a/source4/smb_server/smb2/tcon.c +++ b/source4/smb_server/smb2/tcon.c @@ -245,6 +245,7 @@ static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon const char *service = io->smb2.in.path; struct share_config *scfg; const char *sharetype; + uint64_t ntvfs_caps = 0; if (strncmp(service, "\\\\", 2) == 0) { const char *p = strchr(service+2, '\\'); @@ -283,9 +284,12 @@ static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon } req->tcon = tcon; + ntvfs_caps = NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; + /* init ntvfs function pointers */ status = ntvfs_init_connection(tcon, scfg, type, req->smb_conn->negotiate.protocol, + ntvfs_caps, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c index 9566f5ee29..3f8edd40e8 100644 --- a/source4/torture/libnet/libnet_BecomeDC.c +++ b/source4/torture/libnet/libnet_BecomeDC.c @@ -56,16 +56,9 @@ struct test_become_dc_state { struct drsuapi_DsReplicaObjectListItemEx *last_object; } schema_part; - struct { - const char *samdb_ldb; - const char *domaindn_ldb; - const char *configdn_ldb; - const char *schemadn_ldb; - const char *secrets_ldb; - const char *templates_ldb; - const char *secrets_keytab; - const char *dns_keytab; - } path; + const char *targetdir; + + struct loadparm_context *lp_ctx; }; static NTSTATUS test_become_dc_prepare_db(void *private_data, @@ -73,6 +66,14 @@ static NTSTATUS test_become_dc_prepare_db(void *private_data, { struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state); struct provision_settings settings; + NTSTATUS status; + bool ok; + struct loadparm_context *lp_ctx = loadparm_init(s); + char *smbconf; + + if (!lp_ctx) { + return NT_STATUS_NO_MEMORY; + } settings.dns_name = p->dest_dsa->dns_name; settings.site_name = p->dest_dsa->site_name; @@ -80,21 +81,46 @@ static NTSTATUS test_become_dc_prepare_db(void *private_data, settings.domain_dn_str = p->domain->dn_str; settings.config_dn_str = p->forest->config_dn_str; settings.schema_dn_str = p->forest->schema_dn_str; - settings.invocation_id = &p->dest_dsa->invocation_id; settings.netbios_name = p->dest_dsa->netbios_name; settings.realm = torture_join_dom_dns_name(s->tj); settings.domain = torture_join_dom_netbios_name(s->tj); - settings.ntds_guid = &p->dest_dsa->ntds_guid; - settings.ntds_dn_str = p->dest_dsa->ntds_dn_str; settings.machine_password = cli_credentials_get_password(s->machine_account); - settings.samdb_ldb = s->path.samdb_ldb; - settings.secrets_ldb = s->path.secrets_ldb; - settings.secrets_keytab = s->path.secrets_keytab; - settings.schemadn_ldb = s->path.schemadn_ldb; - settings.configdn_ldb = s->path.configdn_ldb; - settings.domaindn_ldb = s->path.domaindn_ldb; - - return provision_bare(s, s->tctx->lp_ctx, &settings); + settings.targetdir = s->targetdir; + + status = provision_bare(s, s->lp_ctx, &settings); + + smbconf = talloc_asprintf(lp_ctx, "%s/%s", s->targetdir, "/etc/smb.conf"); + + ok = lp_load(lp_ctx, smbconf); + if (!ok) { + DEBUG(0,("Failed load freshly generated smb.conf '%s'\n", smbconf)); + return NT_STATUS_INVALID_PARAMETER; + } + + s->ldb = ldb_wrap_connect(s, lp_ctx, lp_sam_url(lp_ctx), + system_session(s, lp_ctx), + NULL, 0, NULL); + if (!s->ldb) { + DEBUG(0,("Failed to open '%s'\n", lp_sam_url(lp_ctx))); + return NT_STATUS_INTERNAL_DB_ERROR; + } + + ok = samdb_set_ntds_invocation_id(s->ldb, &p->dest_dsa->invocation_id); + if (!ok) { + DEBUG(0,("Failed to set cached ntds invocationId\n")); + return NT_STATUS_FOOBAR; + } + ok = samdb_set_ntds_objectGUID(s->ldb, &p->dest_dsa->ntds_guid); + if (!ok) { + DEBUG(0,("Failed to set cached ntds objectGUID\n")); + return NT_STATUS_FOOBAR; + } + + s->lp_ctx = lp_ctx; + + return NT_STATUS_OK; + + } static NTSTATUS test_become_dc_check_options(void *private_data, @@ -140,6 +166,7 @@ static NTSTATUS test_apply_schema(struct test_become_dc_state *s, struct ldb_val prefixMap_val; struct ldb_message_element *prefixMap_el; struct ldb_val schemaInfo_val; + char *sam_ldb_path; uint32_t i; int ret; bool ok; @@ -325,13 +352,14 @@ static NTSTATUS test_apply_schema(struct test_become_dc_state *s, talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */ s->schema = NULL; - DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema: %s\n", s->path.samdb_ldb)); - s->ldb = ldb_wrap_connect(s, s->tctx->lp_ctx, s->path.samdb_ldb, + sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb"); + DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema: %s\n", sam_ldb_path)); + s->ldb = ldb_wrap_connect(s, s->tctx->lp_ctx, sam_ldb_path, system_session(s, s->tctx->lp_ctx), NULL, 0, NULL); if (!s->ldb) { DEBUG(0,("Failed to open '%s'\n", - s->path.samdb_ldb)); + sam_ldb_path)); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -392,7 +420,8 @@ static NTSTATUS test_become_dc_schema_chunk(void *private_data, } if (!s->schema) { - s->self_made_schema = talloc_zero(s, struct dsdb_schema); + s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx)); + NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema); status = dsdb_load_oid_mappings_drsuapi(s->self_made_schema, mapping_ctr); @@ -564,33 +593,24 @@ bool torture_net_become_dc(struct torture_context *torture) struct ldb_message *msg; int ldb_ret; uint32_t i; + char *sam_ldb_path; + + char *location = NULL; + torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location), + "torture_temp_dir should return NT_STATUS_OK" ); s = talloc_zero(torture, struct test_become_dc_state); if (!s) return false; s->tctx = torture; + s->lp_ctx = torture->lp_ctx; s->netbios_name = lp_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc"); if (!s->netbios_name || !s->netbios_name[0]) { s->netbios_name = "smbtorturedc"; } - s->path.samdb_ldb = talloc_asprintf(s, "%s_samdb.ldb", s->netbios_name); - if (!s->path.samdb_ldb) return false; - s->path.domaindn_ldb = talloc_asprintf(s, "%s_domain.ldb", s->netbios_name); - if (!s->path.domaindn_ldb) return false; - s->path.configdn_ldb = talloc_asprintf(s, "%s_config.ldb", s->netbios_name); - if (!s->path.configdn_ldb) return false; - s->path.schemadn_ldb = talloc_asprintf(s, "%s_schema.ldb", s->netbios_name); - if (!s->path.schemadn_ldb) return false; - s->path.secrets_ldb = talloc_asprintf(s, "%s_secrets.ldb", s->netbios_name); - if (!s->path.secrets_ldb) return false; - s->path.templates_ldb = talloc_asprintf(s, "%s_templates.ldb", s->netbios_name); - if (!s->path.templates_ldb) return false; - s->path.secrets_keytab = talloc_asprintf(s, "%s_secrets.keytab", s->netbios_name); - if (!s->path.secrets_keytab) return false; - s->path.dns_keytab = talloc_asprintf(s, "%s_dns.keytab", s->netbios_name); - if (!s->path.dns_keytab) return false; + s->targetdir = location; /* Join domain as a member server. */ s->tj = torture_join_domain(torture, s->netbios_name, @@ -664,13 +684,14 @@ bool torture_net_become_dc(struct torture_context *torture) talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */ s->schema = NULL; - DEBUG(0,("Reopen the SAM LDB with system credentials and all replicated data: %s\n", s->path.samdb_ldb)); - s->ldb = ldb_wrap_connect(s, torture->lp_ctx, s->path.samdb_ldb, - system_session(s, torture->lp_ctx), + sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb"); + DEBUG(0,("Reopen the SAM LDB with system credentials and all replicated data: %s\n", sam_ldb_path)); + s->ldb = ldb_wrap_connect(s, s->lp_ctx, sam_ldb_path, + system_session(s, s->lp_ctx), NULL, 0, NULL); if (!s->ldb) { DEBUG(0,("Failed to open '%s'\n", - s->path.samdb_ldb)); + sam_ldb_path)); ret = false; goto cleanup; } @@ -682,6 +703,7 @@ bool torture_net_become_dc(struct torture_context *torture) goto cleanup; } + /* Make sure we get this from the command line */ if (lp_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { talloc_free(s); return ret; diff --git a/source4/torture/libnet/libnet_user.c b/source4/torture/libnet/libnet_user.c index 31300a7937..5446087034 100644 --- a/source4/torture/libnet/libnet_user.c +++ b/source4/torture/libnet/libnet_user.c @@ -339,9 +339,9 @@ static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" }; const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" }; const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" }; - const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL), + const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED), (ACB_NORMAL | ACB_PWNOEXP), - (ACB_NORMAL) }; + (ACB_NORMAL | ACB_PW_EXPIRED) }; const char *homedir, *homedrive, *logonscript; struct timeval now; int i, testfld; diff --git a/source4/torture/libnet/userman.c b/source4/torture/libnet/userman.c index 5ce0a64022..a5d8540d7b 100644 --- a/source4/torture/libnet/userman.c +++ b/source4/torture/libnet/userman.c @@ -88,9 +88,9 @@ static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p, const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" }; const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" }; const char *homedir, *homedrive, *logonscript; - const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL), + const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED), (ACB_NORMAL | ACB_PWNOEXP), - (ACB_NORMAL) }; + (ACB_NORMAL | ACB_PW_EXPIRED) }; NTSTATUS status; struct timeval now; @@ -201,7 +201,7 @@ static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p, break; } - printf(((i < num_changes - 1) ? "%s," : "%s"), fldname); + torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname); } torture_comment(tctx, "]\n"); diff --git a/source4/torture/local/torture.c b/source4/torture/local/torture.c index 3273015347..bb6e21ed4f 100644 --- a/source4/torture/local/torture.c +++ b/source4/torture/local/torture.c @@ -43,6 +43,9 @@ static bool test_provision(struct torture_context *tctx) { NTSTATUS status; struct provision_settings settings; + char *location = NULL; + torture_assert_ntstatus_ok(tctx, torture_temp_dir(tctx, "torture_provision", &location), + "torture_temp_dir should return NT_STATUS_OK" ); settings.dns_name = "example.com"; settings.site_name = "SOME-SITE-NAME"; @@ -57,14 +60,7 @@ static bool test_provision(struct torture_context *tctx) settings.ntds_guid = NULL; settings.ntds_dn_str = NULL; settings.machine_password = "geheim"; - settings.samdb_ldb = NULL; - settings.secrets_ldb = NULL; - settings.secrets_keytab = NULL; - settings.schemadn_ldb = NULL; - settings.configdn_ldb = NULL; - settings.domaindn_ldb = NULL; - settings.templates_ldb = NULL; - settings.dns_keytab = NULL; + settings.targetdir = location; status = provision_bare(tctx, tctx->lp_ctx, &settings); diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c index fa69c92caa..7fd74e3cbe 100644 --- a/source4/torture/raw/chkpath.c +++ b/source4/torture/raw/chkpath.c @@ -150,7 +150,7 @@ static bool test_chkpath(struct smbcli_state *cli, struct torture_context *tctx) ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\f\\o\\o\\..\\..\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); - ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\\\..\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 7ac88c0996..1926b12128 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -24,6 +24,9 @@ #include "libcli/libcli.h" #include "torture/util.h" #include "lib/events/events.h" +#include "param/param.h" +#include "lib/cmdline/popt_common.h" +#include "libcli/resolve/resolve.h" #define CHECK_VAL(v, correct) do { \ if ((v) != (correct)) { \ @@ -32,6 +35,13 @@ ret = false; \ }} while (0) +#define CHECK_RANGE(v, min, max) do { \ + if ((v) < (min) || (v) > (max)) { \ + torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got %d - should be between %d and %d\n", \ + __location__, #v, (int)v, (int)min, (int)max); \ + ret = false; \ + }} while (0) + #define CHECK_STRMATCH(v, correct) do { \ if (!v || strstr((v),(correct)) == NULL) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got '%s' - should be '%s'\n", \ @@ -61,16 +71,30 @@ static struct { /* a handler function for oplock break requests. Ack it as a break to level II if possible */ -static bool oplock_handler_ack_to_levelII(struct smbcli_transport *transport, - uint16_t tid, uint16_t fnum, - uint8_t level, void *private) +static bool oplock_handler_ack_to_given(struct smbcli_transport *transport, + uint16_t tid, uint16_t fnum, + uint8_t level, void *private) { struct smbcli_tree *tree = (struct smbcli_tree *)private; + const char *name; + break_info.fnum = fnum; break_info.level = level; break_info.count++; - printf("Acking to level II in oplock handler\n"); + switch (level) { + case OPLOCK_BREAK_TO_LEVEL_II: + name = "level II"; + break; + case OPLOCK_BREAK_TO_NONE: + name = "none"; + break; + default: + name = "unknown"; + break_info.failures++; + } + printf("Acking to %s [0x%02X] in oplock handler\n", + name, level); return smbcli_oplock_ack(tree, fnum, level); } @@ -92,6 +116,21 @@ static bool oplock_handler_ack_to_none(struct smbcli_transport *transport, return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE); } +/* + a handler function for oplock break requests. Let it timeout +*/ +static bool oplock_handler_timeout(struct smbcli_transport *transport, + uint16_t tid, uint16_t fnum, + uint8_t level, void *private) +{ + break_info.fnum = fnum; + break_info.level = level; + break_info.count++; + + printf("Let oplock break timeout\n"); + return true; +} + static void oplock_handler_close_recv(struct smbcli_request *req) { NTSTATUS status; @@ -131,6 +170,32 @@ static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t ti return true; } +static bool open_connection_no_level2_oplocks(struct torture_context *tctx, + struct smbcli_state **c) +{ + NTSTATUS status; + + struct smbcli_options options; + + lp_smbcli_options(tctx->lp_ctx, &options); + + options.use_level2_oplocks = false; + + status = smbcli_full_connection(tctx, c, + torture_setting_string(tctx, "host", NULL), + lp_smb_ports(tctx->lp_ctx), + torture_setting_string(tctx, "share", NULL), + NULL, cmdline_credentials, + lp_resolve_context(tctx->lp_ctx), + tctx->ev, &options); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to open connection - %s\n", nt_errstr(status)); + return false; + } + + return true; +} + static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_exclusive1.dat"; @@ -147,7 +212,7 @@ static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -212,7 +277,7 @@ static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -307,7 +372,7 @@ static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -376,7 +441,7 @@ static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -395,7 +460,7 @@ static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbc torture_comment(tctx, "open with exclusive oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; status = smb_raw_open(cli1->tree, tctx, &io); @@ -440,8 +505,8 @@ static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -460,7 +525,7 @@ static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbc torture_comment(tctx, "open with exclusive oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; @@ -515,7 +580,7 @@ static bool test_raw_oplock_exclusive6(struct torture_context *tctx, struct smbc smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -588,7 +653,7 @@ static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -672,7 +737,7 @@ static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -750,7 +815,7 @@ static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -814,7 +879,7 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -833,7 +898,7 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a self read should not cause a break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -877,7 +942,7 @@ static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -896,7 +961,7 @@ static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a 2nd open should give a break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -942,7 +1007,7 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -961,8 +1026,8 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a 2nd open should give a break to level II if the first open allowed shared read\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; @@ -1022,7 +1087,7 @@ static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1092,7 +1157,7 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1111,7 +1176,7 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1161,7 +1226,7 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1193,7 +1258,7 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1212,8 +1277,8 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "third oplocked open should grant level2 without break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; @@ -1266,7 +1331,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1297,7 +1362,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_ CHECK_VAL(break_info.failures, 0); CHECK_VAL(io.ntcreatex.out.oplock_level, 0); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1375,7 +1440,7 @@ static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1396,7 +1461,7 @@ static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1450,7 +1515,7 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1471,7 +1536,7 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if setpathinfo allocation size breaks oplocks.\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1524,8 +1589,8 @@ static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1544,7 +1609,7 @@ static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | @@ -1602,7 +1667,7 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1621,7 +1686,7 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1678,7 +1743,7 @@ static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1699,7 +1764,7 @@ static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if qpathinfo all info breaks a batch oplock (should not).\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1750,8 +1815,8 @@ static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1770,7 +1835,7 @@ static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | @@ -1832,7 +1897,7 @@ static bool test_raw_oplock_batch17(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1910,7 +1975,7 @@ static bool test_raw_oplock_batch18(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1994,7 +2059,7 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname2); smbcli_unlink(cli1->tree, fname3); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2096,7 +2161,7 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname2); smbcli_unlink(cli1->tree, fname3); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2204,6 +2269,334 @@ done: return ret; } +static bool test_raw_oplock_batch21(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch21.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + struct smb_echo e; + uint16_t fnum=0; + char c = 0; + ssize_t wr; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + /* + with a batch oplock we get a break + */ + torture_comment(tctx, "open with batch oplock\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + torture_comment(tctx, "writing should not generate a break\n"); + wr = smbcli_write(cli1->tree, fnum, 0, &c, 0, 1); + CHECK_VAL(wr, 1); + CHECK_STATUS(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_OK); + + ZERO_STRUCT(e); + e.in.repeat_count = 1; + status = smb_raw_echo(cli1->transport, &e); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + +static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch22.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0; + struct timeval tv; + int timeout = torture_setting_int(tctx, "oplocktimeout", 30); + int te; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT22 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + /* + with a batch oplock we get a break + */ + torture_comment(tctx, "open with batch oplock\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + torture_comment(tctx, "a 2nd open shoud not succeed after the oplock break timeout\n"); + tv = timeval_current(); + smbcli_oplock_handler(cli1->transport, oplock_handler_timeout, cli1->tree); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + te = (int)timeval_elapsed(&tv); + CHECK_RANGE(te, timeout - 1, timeout + 15); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open shoud succeed after the oplock release without break\n"); + tv = timeval_current(); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + te = (int)timeval_elapsed(&tv); + /* it should come in without delay */ + CHECK_RANGE(te+1, 0, timeout); + fnum2 = io.ntcreatex.out.file.fnum; + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli1->tree, fnum2); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + +static bool test_raw_oplock_batch23(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch23.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0,fnum3=0; + struct smbcli_state *cli3 = NULL; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT23 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + + ret = open_connection_no_level2_oplocks(tctx, &cli3); + CHECK_VAL(ret, true); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + torture_comment(tctx, "a open and ask for a batch oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree); + + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open without level2 oplock support should generate a break to level2\n"); + status = smb_raw_open(cli3->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum3 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 3rd open with level2 oplock support should not generate a break\n"); + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum2 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->tree, fnum2); + smbcli_close(cli3->tree, fnum3); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smb_raw_exit(cli3->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + +static bool test_raw_oplock_batch24(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch24.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum2=0,fnum3=0; + struct smbcli_state *cli3 = NULL; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + + ret = open_connection_no_level2_oplocks(tctx, &cli3); + CHECK_VAL(ret, true); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + torture_comment(tctx, "a open without level support and ask for a batch oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree); + + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli3->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum3 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open with level2 oplock support should generate a break to none\n"); + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum2 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum3); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE); + CHECK_VAL(break_info.failures, 0); + + smbcli_close(cli3->tree, fnum3); + smbcli_close(cli2->tree, fnum2); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smb_raw_exit(cli3->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2237,6 +2630,10 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH18", test_raw_oplock_batch18); torture_suite_add_2smb_test(suite, "BATCH19", test_raw_oplock_batch19); torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20); + torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21); + torture_suite_add_2smb_test(suite, "BATCH22", test_raw_oplock_batch22); + torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23); + torture_suite_add_2smb_test(suite, "BATCH24", test_raw_oplock_batch24); return suite; } diff --git a/source4/torture/util.h b/source4/torture/util.h index c5219a5aaa..477a828120 100644 --- a/source4/torture/util.h +++ b/source4/torture/util.h @@ -29,19 +29,13 @@ struct provision_settings { const char *schema_dn_str; const struct GUID *invocation_id; const char *netbios_name; + const char *host_ip; const char *realm; const char *domain; const struct GUID *ntds_guid; const char *ntds_dn_str; const char *machine_password; - const char *samdb_ldb; - const char *secrets_ldb; - const char *secrets_keytab; - const char *schemadn_ldb; - const char *configdn_ldb; - const char *domaindn_ldb; - const char *templates_ldb; - const char *dns_keytab; + const char *targetdir; }; NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, diff --git a/source4/torture/util_provision.c b/source4/torture/util_provision.c index 2a1e9256f5..d7c8f479e6 100644 --- a/source4/torture/util_provision.c +++ b/source4/torture/util_provision.c @@ -18,206 +18,22 @@ */ #include "includes.h" -#include "dsdb/samdb/samdb.h" -#include "lib/appweb/ejs/ejs.h" -#include "lib/appweb/ejs/ejsInternal.h" -#include "scripting/ejs/smbcalls.h" #include "auth/auth.h" #include "lib/ldb_wrap.h" #include "torture/util.h" -static EjsId eid; -static int ejs_error; - -static void test_ejs_exception(const char *reason) -{ - Ejs *ep = ejsPtr(eid); - ejsSetErrorMsg(eid, "%s", reason); - fprintf(stderr, "%s", ep->error); - ejs_error = 127; -} - -static int test_run_ejs(char *script) -{ - EjsHandle handle = 0; - MprVar result; - char *emsg; - TALLOC_CTX *mem_ctx = talloc_new(NULL); - struct MprVar *return_var; - - mprSetCtx(mem_ctx); - - if (ejsOpen(NULL, NULL, NULL) != 0) { - d_printf("ejsOpen(): unable to initialise EJS subsystem\n"); - ejs_error = 127; - goto failed; - } - - smb_setup_ejs_functions(test_ejs_exception); - - if ((eid = ejsOpenEngine(handle, 0)) == (EjsId)-1) { - d_printf("smbscript: ejsOpenEngine(): unable to initialise an EJS engine\n"); - ejs_error = 127; - goto failed; - } - - mprSetVar(ejsGetGlobalObject(eid), "ARGV", mprList("ARGV", NULL)); - - /* run the script */ - if (ejsEvalScript(eid, script, &result, &emsg) == -1) { - d_printf("smbscript: ejsEvalScript(): %s\n", emsg); - if (ejs_error == 0) ejs_error = 127; - goto failed; - } - - return_var = ejsGetReturnValue(eid); - ejs_error = mprVarToNumber(return_var); - -failed: - ejsClose(); - talloc_free(mem_ctx); - return ejs_error; -} - -static NTSTATUS provision_bare_ejs(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - struct provision_settings *settings) -{ - char *ejs; - int ret; - bool ok; - struct ldb_context *ldb; - - DEBUG(0,("Provision for Become-DC test using EJS\n")); - - DEBUG(0,("New Server[%s] in Site[%s]\n", settings->dns_name, - settings->site_name)); - - DEBUG(0,("DSA Instance [%s]\n" - "\tobjectGUID[%s]\n" - "\tinvocationId[%s]\n", - settings->ntds_dn_str, - GUID_string(mem_ctx, settings->ntds_guid), - GUID_string(mem_ctx, settings->invocation_id))); - - DEBUG(0,("Pathes under PRIVATEDIR[%s]\n" - "SAMDB[%s] SECRETS[%s] KEYTAB[%s]\n", - lp_private_dir(lp_ctx), - settings->samdb_ldb, - settings->secrets_ldb, - settings->secrets_keytab)); - - DEBUG(0,("Schema Partition[%s => %s]\n", - settings->schema_dn_str, settings->schemadn_ldb)); - - DEBUG(0,("Config Partition[%s => %s]\n", - settings->config_dn_str, settings->configdn_ldb)); - - DEBUG(0,("Domain Partition[%s => %s]\n", - settings->domain_dn_str, settings->domaindn_ldb)); - - ejs = talloc_asprintf(mem_ctx, - "libinclude(\"base.js\");\n" - "libinclude(\"provision.js\");\n" - "\n" - "function message() { print(vsprintf(arguments)); }\n" - "\n" - "var subobj = provision_guess();\n" - "subobj.ROOTDN = \"%s\";\n" - "subobj.DOMAINDN = \"%s\";\n" - "subobj.DOMAINDN_LDB = \"%s\";\n" - "subobj.CONFIGDN = \"%s\";\n" - "subobj.CONFIGDN_LDB = \"%s\";\n" - "subobj.SCHEMADN = \"%s\";\n" - "subobj.SCHEMADN_LDB = \"%s\";\n" - "subobj.HOSTNAME = \"%s\";\n" - "subobj.REALM = \"%s\";\n" - "subobj.DOMAIN = \"%s\";\n" - "subobj.DEFAULTSITE = \"%s\";\n" - "\n" - "subobj.KRBTGTPASS = \"_NOT_USED_\";\n" - "subobj.MACHINEPASS = \"%s\";\n" - "subobj.ADMINPASS = \"_NOT_USED_\";\n" - "\n" - "var paths = provision_default_paths(subobj);\n" - "paths.samdb = \"%s\";\n" - "paths.secrets = \"%s\";\n" - "paths.templates = \"%s\";\n" - "paths.keytab = \"%s\";\n" - "paths.dns_keytab = \"%s\";\n" - "\n" - "var system_session = system_session();\n" - "\n" - "var ok = provision_become_dc(subobj, message, true, paths, system_session);\n" - "assert(ok);\n" - "\n" - "return 0;\n", - settings->root_dn_str, /* subobj.ROOTDN */ - settings->domain_dn_str, /* subobj.DOMAINDN */ - settings->domaindn_ldb, /* subobj.DOMAINDN_LDB */ - settings->config_dn_str, /* subobj.CONFIGDN */ - settings->configdn_ldb, /* subobj.CONFIGDN_LDB */ - settings->schema_dn_str, /* subobj.SCHEMADN */ - settings->schemadn_ldb, /* subobj.SCHEMADN_LDB */ - settings->netbios_name, /* subobj.HOSTNAME */ - settings->realm,/* subobj.REALM */ - settings->domain,/* subobj.DOMAIN */ - settings->site_name, /* subobj.DEFAULTSITE */ - settings->machine_password,/* subobj.MACHINEPASS */ - settings->samdb_ldb, /* paths.samdb */ - settings->templates_ldb, /* paths.templates */ - settings->secrets_ldb, /* paths.secrets */ - settings->secrets_keytab, /* paths.keytab */ - settings->dns_keytab); /* paths.dns_keytab */ - NT_STATUS_HAVE_NO_MEMORY(ejs); - - ret = test_run_ejs(ejs); - if (ret != 0) { - DEBUG(0,("Failed to run ejs script: %d:\n%s", - ret, ejs)); - talloc_free(ejs); - return NT_STATUS_FOOBAR; - } - talloc_free(ejs); - - DEBUG(0,("Open the SAM LDB with system credentials: %s\n", - settings->samdb_ldb)); - - ldb = ldb_wrap_connect(mem_ctx, lp_ctx, settings->samdb_ldb, - system_session(mem_ctx, lp_ctx), - NULL, 0, NULL); - if (!ldb) { - DEBUG(0,("Failed to open '%s'\n", - settings->samdb_ldb)); - return NT_STATUS_INTERNAL_DB_ERROR; - } - - ok = samdb_set_ntds_invocation_id(ldb, settings->invocation_id); - if (!ok) { - DEBUG(0,("Failed to set cached ntds invocationId\n")); - return NT_STATUS_FOOBAR; - } - ok = samdb_set_ntds_objectGUID(ldb, settings->ntds_guid); - if (!ok) { - DEBUG(0,("Failed to set cached ntds objectGUID\n")); - return NT_STATUS_FOOBAR; - } - - return NT_STATUS_OK; -} - #include "param/param.h" #include <Python.h> #include "scripting/python/modules.h" -static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - struct provision_settings *settings) +NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, + struct provision_settings *settings) { bool ok; PyObject *provision_mod, *provision_dict, *provision_fn, *result, *parameters; struct ldb_context *ldb; - + char *sam_ldb_path; + DEBUG(0,("Provision for Become-DC test using python\n")); py_load_samba_modules(); @@ -239,10 +55,10 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - provision_fn = PyDict_GetItemString(provision_dict, "provision"); + provision_fn = PyDict_GetItemString(provision_dict, "provision_become_dc"); if (provision_fn == NULL) { PyErr_Print(); - DEBUG(0, ("Unable to get provision function\n")); + DEBUG(0, ("Unable to get provision_become_dc function\n")); return NT_STATUS_UNSUCCESSFUL; } @@ -256,56 +72,45 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, settings->ntds_guid == NULL?"None":GUID_string(mem_ctx, settings->ntds_guid), settings->invocation_id == NULL?"None":GUID_string(mem_ctx, settings->invocation_id))); - DEBUG(0,("Pathes under PRIVATEDIR[%s]\n" - "SAMDB[%s] SECRETS[%s] KEYTAB[%s]\n", - lp_private_dir(lp_ctx), - settings->samdb_ldb, - settings->secrets_ldb, - settings->secrets_keytab)); - - DEBUG(0,("Schema Partition[%s => %s]\n", - settings->schema_dn_str, settings->schemadn_ldb)); - - DEBUG(0,("Config Partition[%s => %s]\n", - settings->config_dn_str, settings->configdn_ldb)); - - DEBUG(0,("Domain Partition[%s => %s]\n", - settings->domain_dn_str, settings->domaindn_ldb)); - + DEBUG(0,("Pathes under targetdir[%s]\n", + settings->targetdir)); parameters = PyDict_New(); PyDict_SetItemString(parameters, "rootdn", PyString_FromString(settings->root_dn_str)); - if (settings->domaindn_ldb != NULL) - PyDict_SetItemString(parameters, "domaindn_ldb", - PyString_FromString(settings->domaindn_ldb)); - if (settings->config_dn_str != NULL) - PyDict_SetItemString(parameters, "configdn", - PyString_FromString(settings->config_dn_str)); - if (settings->configdn_ldb != NULL) - PyDict_SetItemString(parameters, "configdn_ldb", - PyString_FromString(settings->configdn_ldb)); - if (settings->schema_dn_str != NULL) - PyDict_SetItemString(parameters, "schema_dn_str", - PyString_FromString(settings->schema_dn_str)); - if (settings->schemadn_ldb != NULL) - PyDict_SetItemString(parameters, "schemadn_ldb", - PyString_FromString(settings->schemadn_ldb)); + if (settings->targetdir != NULL) + PyDict_SetItemString(parameters, "targetdir", + PyString_FromString(settings->targetdir)); + PyDict_SetItemString(parameters, "setup_dir", + PyString_FromString("setup")); PyDict_SetItemString(parameters, "hostname", PyString_FromString(settings->netbios_name)); - PyDict_SetItemString(parameters, "sitename", - PyString_FromString(settings->site_name)); + PyDict_SetItemString(parameters, "domain", + PyString_FromString(settings->domain)); + PyDict_SetItemString(parameters, "realm", + PyString_FromString(settings->realm)); + if (settings->root_dn_str) + PyDict_SetItemString(parameters, "rootdn", + PyString_FromString(settings->root_dn_str)); + + if (settings->domain_dn_str) + PyDict_SetItemString(parameters, "domaindn", + PyString_FromString(settings->domain_dn_str)); + + if (settings->schema_dn_str) + PyDict_SetItemString(parameters, "schemadn", + PyString_FromString(settings->schema_dn_str)); + + if (settings->config_dn_str) + PyDict_SetItemString(parameters, "configdn", + PyString_FromString(settings->config_dn_str)); + + if (settings->site_name) + PyDict_SetItemString(parameters, "sitename", + PyString_FromString(settings->site_name)); + PyDict_SetItemString(parameters, "machinepass", - PyString_FromString(settings->machine_password)); - if (settings->samdb_ldb != NULL) - PyDict_SetItemString(parameters, "samdb", - PyString_FromString(settings->samdb_ldb)); - if (settings->secrets_ldb != NULL) - PyDict_SetItemString(parameters, "secrets_ldb", - PyString_FromString(settings->secrets_ldb)); - if (settings->secrets_keytab != NULL) - PyDict_SetItemString(parameters, "secrets_keytab", - PyString_FromString(settings->secrets_keytab)); + PyString_FromString(settings->machine_password)); result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters); @@ -317,39 +122,5 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - DEBUG(0,("Open the SAM LDB with system credentials: %s\n", - settings->samdb_ldb)); - - ldb = ldb_wrap_connect(mem_ctx, lp_ctx, settings->samdb_ldb, - system_session(mem_ctx, lp_ctx), - NULL, 0, NULL); - if (!ldb) { - DEBUG(0,("Failed to open '%s'\n", settings->samdb_ldb)); - return NT_STATUS_INTERNAL_DB_ERROR; - } - - ok = samdb_set_ntds_invocation_id(ldb, settings->invocation_id); - if (!ok) { - DEBUG(0,("Failed to set cached ntds invocationId\n")); - return NT_STATUS_FOOBAR; - } - ok = samdb_set_ntds_objectGUID(ldb, settings->ntds_guid); - if (!ok) { - DEBUG(0,("Failed to set cached ntds objectGUID\n")); - return NT_STATUS_FOOBAR; - } - return NT_STATUS_OK; } - -NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, - struct provision_settings *settings) -{ - if (getenv("PROVISION_EJS")) { - return provision_bare_ejs(mem_ctx, lp_ctx, settings); - } else { - return provision_bare_py(mem_ctx, lp_ctx, settings); - } -} - - diff --git a/source4/torture/util_smb.c b/source4/torture/util_smb.c index ddf7b85c63..ba62f3789c 100644 --- a/source4/torture/util_smb.c +++ b/source4/torture/util_smb.c @@ -478,6 +478,9 @@ _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx, lp_smbcli_options(tctx->lp_ctx, &options); + options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true); + options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true); + status = smbcli_full_connection(mem_ctx, c, hostname, lp_smb_ports(tctx->lp_ctx), sharename, NULL, @@ -489,9 +492,6 @@ _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx, return false; } - (*c)->transport->options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", false); - (*c)->transport->options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", false); - return true; } |