diff options
27 files changed, 1491 insertions, 260 deletions
diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c index 9189640150..4cb8d2b304 100644 --- a/source4/auth/auth_sam.c +++ b/source4/auth/auth_sam.c @@ -226,7 +226,9 @@ static NTSTATUS authsam_authenticate(struct auth_context *auth_context, { struct samr_Password *lm_pwd, *nt_pwd; NTSTATUS nt_status; - uint16_t acct_flags = samdb_result_acct_flags(msgs[0], "userAccountControl"); + struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msgs_domain_ref[0], "nCName", NULL); + + uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn); /* Quit if the account was locked out. */ if (acct_flags & ACB_AUTOLOCK) { diff --git a/source4/auth/sam.c b/source4/auth/sam.c index fdd7de7c71..abcb72f292 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -156,7 +156,7 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, NTTIME now; DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs)); - acct_flags = samdb_result_acct_flags(msg, "userAccountControl"); + acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); acct_expiry = samdb_result_nttime(msg, "accountExpires", 0); must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, @@ -186,22 +186,20 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, return NT_STATUS_ACCOUNT_EXPIRED; } - if (!(acct_flags & ACB_PWNOEXP)) { - /* check for immediate expiry "must change at next logon" */ - if (must_change_time == 0 && last_set_time != 0) { - DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", - name_for_logs)); - return NT_STATUS_PASSWORD_MUST_CHANGE; - } + /* check for immediate expiry "must change at next logon" */ + if (!(acct_flags & ACB_PWNOEXP) && (must_change_time == 0 && last_set_time != 0)) { + DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", + name_for_logs)); + return NT_STATUS_PASSWORD_MUST_CHANGE; + } - /* check for expired password */ - if ((must_change_time != 0) && (must_change_time < now)) { - DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", - name_for_logs)); - DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n", - nt_time_string(mem_ctx, must_change_time))); - return NT_STATUS_PASSWORD_EXPIRED; - } + /* check for expired password (dynamicly gnerated in samdb_result_acct_flags) */ + if (acct_flags & ACB_PW_EXPIRED) { + DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", + name_for_logs)); + DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n", + nt_time_string(mem_ctx, must_change_time))); + return NT_STATUS_PASSWORD_EXPIRED; } /* Test workstation. Workstation list is comma separated. */ @@ -267,6 +265,7 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_conte struct dom_sid **groupSIDs = NULL; struct dom_sid *account_sid; struct dom_sid *primary_group_sid; + struct ldb_dn *domain_dn; const char *str; struct ldb_dn *ncname; int i; @@ -368,7 +367,10 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_conte server_info->logon_count = samdb_result_uint(msg, "logonCount", 0); server_info->bad_password_count = samdb_result_uint(msg, "badPwdCount", 0); - server_info->acct_flags = samdb_result_acct_flags(msg, "userAccountControl"); + domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", NULL); + + server_info->acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, + msg, domain_dn); server_info->user_session_key = user_sess_key; server_info->lm_session_key = lm_sess_key; diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c index 3dfc6819b7..3d67162d6d 100644 --- a/source4/cluster/ctdb/opendb_ctdb.c +++ b/source4/cluster/ctdb/opendb_ctdb.c @@ -409,10 +409,12 @@ static NTSTATUS odb_ctdb_open_file_pending(struct odb_lock *lck, void *private) /* remove a opendb entry */ -static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle) +static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle, + const char **_delete_path) { struct odb_context *odb = lck->odb; struct opendb_file file; + const char *delete_path = NULL; int i; NTSTATUS status; @@ -448,6 +450,15 @@ static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle) file.num_pending = 0; file.num_entries--; + + if (file.num_entries == 0 && file.delete_on_close) { + delete_path = talloc_strdup(lck, file.path); + NT_STATUS_HAVE_NO_MEMORY(delete_path); + } + + if (_delete_path) { + *_delete_path = delete_path; + } return odb_push_record(lck, &file); } @@ -552,20 +563,20 @@ static NTSTATUS odb_ctdb_set_delete_on_close(struct odb_lock *lck, bool del_on_c people still have the file open */ static NTSTATUS odb_ctdb_get_delete_on_close(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close, - int *open_count, char **path) + DATA_BLOB *key, bool *del_on_close) { NTSTATUS status; struct opendb_file file; struct odb_lock *lck; + (*del_on_close) = false; + lck = odb_lock(odb, odb, key); NT_STATUS_HAVE_NO_MEMORY(lck); status = odb_pull_record(lck, &file); if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { talloc_free(lck); - (*del_on_close) = false; return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { @@ -574,16 +585,6 @@ static NTSTATUS odb_ctdb_get_delete_on_close(struct odb_context *odb, } (*del_on_close) = file.delete_on_close; - if (open_count != NULL) { - (*open_count) = file.num_entries; - } - if (path != NULL) { - *path = talloc_strdup(odb, file.path); - NT_STATUS_HAVE_NO_MEMORY(*path); - if (file.num_entries == 1 && file.entries[0].delete_on_close) { - (*del_on_close) = true; - } - } talloc_free(lck); diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index bee1eac480..c9c0285604 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -596,11 +596,37 @@ struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_ /* pull a set of account_flags from a result set. + + This requires that the attributes: + pwdLastSet + userAccountControl + be included in 'msg' */ -uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr) -{ - uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0); - return samdb_uf2acb(userAccountControl); +uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + struct ldb_message *msg, struct ldb_dn *domain_dn) +{ + uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); + uint32_t acct_flags = samdb_uf2acb(userAccountControl); + if ((userAccountControl & UF_NORMAL_ACCOUNT) && !(userAccountControl & UF_DONT_EXPIRE_PASSWD)) { + NTTIME must_change_time; + NTTIME pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0); + if (pwdLastSet == 0) { + acct_flags |= ACB_PW_EXPIRED; + } else { + NTTIME now; + + must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, + domain_dn, msg); + + /* Test account expire time */ + unix_to_nt_time(&now, time(NULL)); + /* check for expired password */ + if ((must_change_time != 0) && (must_change_time < now)) { + acct_flags |= ACB_PW_EXPIRED; + } + } + } + return acct_flags; } diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 178149a886..905cd4a995 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -396,6 +396,7 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_ struct ldb_message **ret_msg) { int ret; + unsigned int group_type; char *name; struct ldb_message *msg2; struct ldb_dn *dom_dn; @@ -452,6 +453,26 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_ } } + if (ldb_msg_find_element(msg2, "sAMAccountType") != NULL) { + ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified"); + talloc_free(mem_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + group_type = samdb_result_uint(msg2, "groupType", 0); + if (group_type == 0) { + ldb_asprintf_errstring(module->ldb, "groupType invalid"); + talloc_free(mem_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } else { + unsigned int account_type = samdb_gtype2atype(group_type); + ret = samdb_msg_add_uint(module->ldb, msg2, msg2, + "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + } + /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn); @@ -473,6 +494,7 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; + unsigned int user_account_control; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } @@ -485,36 +507,15 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const return LDB_ERR_OPERATIONS_ERROR; } - if (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL) { - - ret = samdb_copy_template(module->ldb, msg2, - "computer", - &errstr); - if (ret) { - ldb_asprintf_errstring(module->ldb, - "samldb_fill_user_or_computer_object: " - "Error copying computer template: %s", - errstr); - talloc_free(mem_ctx); - return ret; - } - } else { - ret = samdb_copy_template(module->ldb, msg2, - "user", - &errstr); - if (ret) { - ldb_asprintf_errstring(module->ldb, - "samldb_fill_user_or_computer_object: Error copying user template: %s\n", - errstr); - talloc_free(mem_ctx); - return ret; - } - /* readd user objectclass */ - ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); - if (ret) { - talloc_free(mem_ctx); - return ret; - } + ret = samdb_copy_template(module->ldb, msg2, + "user", + &errstr); + if (ret) { + ldb_asprintf_errstring(module->ldb, + "samldb_fill_user_or_computer_object: Error copying user template: %s\n", + errstr); + talloc_free(mem_ctx); + return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); @@ -545,14 +546,30 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const } } - /* - TODO: useraccountcontrol: setting value 0 gives 0x200 for users - */ + if (ldb_msg_find_element(msg2, "sAMAccountType") != NULL) { + ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified"); + talloc_free(mem_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + user_account_control = samdb_result_uint(msg2, "userAccountControl", 0); + if (user_account_control == 0) { + ldb_asprintf_errstring(module->ldb, "userAccountControl invalid"); + talloc_free(mem_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } else { + unsigned int account_type = samdb_uf2atype(user_account_control); + ret = samdb_msg_add_uint(module->ldb, msg2, msg2, + "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + } /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn); - /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ + /* TODO: userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ if (ret == 0) { *ret_msg = msg2; @@ -689,7 +706,7 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) } /* is user or computer? */ - if ((samdb_find_attribute(module->ldb, msg, "objectclass", "user") != NULL) || + if ((samdb_find_attribute(module->ldb, msg, "objectclass", "user") != NULL) || (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL)) { /* add all relevant missing objects */ ret = samldb_fill_user_or_computer_object(module, msg, &msg2); @@ -745,6 +762,53 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) return ret; } +/* modify */ +static int samldb_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_message *msg; + struct ldb_message_element *el, *el2; + int ret; + unsigned int group_type, user_account_control, account_type; + if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) { + ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + el = ldb_msg_find_element(req->op.mod.message, "groupType"); + if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) { + req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message); + + group_type = strtoul((const char *)el->values[0].data, NULL, 0); + account_type = samdb_gtype2atype(group_type); + ret = samdb_msg_add_uint(module->ldb, msg, msg, + "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + el2 = ldb_msg_find_element(msg, "sAMAccountType"); + el2->flags = LDB_FLAG_MOD_REPLACE; + } + + el = ldb_msg_find_element(req->op.mod.message, "userAccountControl"); + if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) { + req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message); + + user_account_control = strtoul((const char *)el->values[0].data, NULL, 0); + account_type = samdb_uf2atype(user_account_control); + ret = samdb_msg_add_uint(module->ldb, msg, msg, + "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + el2 = ldb_msg_find_element(msg, "sAMAccountType"); + el2->flags = LDB_FLAG_MOD_REPLACE; + } + return ldb_next_request(module, req); +} + + static int samldb_init(struct ldb_module *module) { return ldb_next_init(module); @@ -754,4 +818,5 @@ _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = { .name = "samldb", .init_context = samldb_init, .add = samldb_add, + .modify = samldb_modify }; diff --git a/source4/lib/ldb/modules/rdn_name.c b/source4/lib/ldb/modules/rdn_name.c index c4de8e8da8..65c044c0f4 100644 --- a/source4/lib/ldb/modules/rdn_name.c +++ b/source4/lib/ldb/modules/rdn_name.c @@ -119,7 +119,8 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) "RDN mismatch on %s: %s (%s)", ldb_dn_get_linearized(msg->dn), rdn_name, rdn_val.data); talloc_free(down_req); - return LDB_ERR_OPERATIONS_ERROR; + /* Match AD's error here */ + return LDB_ERR_INVALID_DN_SYNTAX; } } diff --git a/source4/libnet/libnet_user.c b/source4/libnet/libnet_user.c index d5ccf34a57..678c7a226e 100644 --- a/source4/libnet/libnet_user.c +++ b/source4/libnet/libnet_user.c @@ -534,7 +534,7 @@ static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY); /* account flags change */ - SET_FIELD_UINT32(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS); + SET_FIELD_ACCT_FLAGS(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS); return NT_STATUS_OK; } diff --git a/source4/libnet/libnet_user.h b/source4/libnet/libnet_user.h index ece06f08fc..94aa38464f 100644 --- a/source4/libnet/libnet_user.h +++ b/source4/libnet/libnet_user.h @@ -91,6 +91,14 @@ struct libnet_ModifyUser { mod->fields |= flag; \ } +#define SET_FIELD_ACCT_FLAGS(new, current, mod, field, flag) \ + if (new.field) { \ + if (current->field != new.field) { \ + mod->field = new.field; \ + mod->fields |= flag; \ + } \ + } + struct libnet_UserInfo { struct { diff --git a/source4/librpc/idl/unixinfo.idl b/source4/librpc/idl/unixinfo.idl index 48bc565fff..6929e86e61 100644 --- a/source4/librpc/idl/unixinfo.idl +++ b/source4/librpc/idl/unixinfo.idl @@ -42,8 +42,8 @@ import "security.idl"; typedef struct { NTSTATUS status; - utf8string homedir; - utf8string shell; + [charset(UTF8),string] uint8 homedir[]; + [charset(UTF8),string] uint8 shell[]; } unixinfo_GetPWUidInfo; /******************/ diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 36144d0406..d8cb67686b 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -118,9 +118,10 @@ _PUBLIC_ NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private) /* remove a opendb entry */ -_PUBLIC_ NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle) +_PUBLIC_ NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle, + const char **delete_path) { - return ops->odb_close_file(lck, file_handle); + return ops->odb_close_file(lck, file_handle, delete_path); } @@ -154,10 +155,9 @@ _PUBLIC_ NTSTATUS odb_set_delete_on_close(struct odb_lock *lck, bool del_on_clos people still have the file open */ _PUBLIC_ NTSTATUS odb_get_delete_on_close(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close, - int *open_count, char **path) + DATA_BLOB *key, bool *del_on_close) { - return ops->odb_get_delete_on_close(odb, key, del_on_close, open_count, path); + return ops->odb_get_delete_on_close(odb, key, del_on_close); } diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 9591bcf6b9..33f2e1c88d 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -32,13 +32,13 @@ struct opendb_ops { uint32_t open_disposition, bool break_to_none, 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); + NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle, + const char **delete_path); NTSTATUS (*odb_remove_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_rename)(struct odb_lock *lck, const char *path); NTSTATUS (*odb_set_delete_on_close)(struct odb_lock *lck, bool del_on_close); NTSTATUS (*odb_get_delete_on_close)(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close, - int *open_count, char **path); + DATA_BLOB *key, bool *del_on_close); NTSTATUS (*odb_can_open)(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index fe5a0a8864..37c1c0850b 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -376,8 +376,26 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, exclusive oplocks afterwards. */ for (i=0;i<file->num_entries;i++) { if (file->entries[i].oplock_level == OPLOCK_EXCLUSIVE) { + bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II; + /* if this is an attribute only access + * it doesn't conflict with an EXCLUSIVE oplock + * but we'll not grant the oplock below + */ + attrs_only = access_attributes_only(access_mask, + open_disposition, + break_to_none); + if (attrs_only) { + break; + } + /* + * send an oplock break to the holder of the + * oplock and tell caller to retry later + */ + if (break_to_none) { + oplock_return = OPLOCK_BREAK_TO_NONE; + } odb_oplock_break_send(odb, &file->entries[i], - OPLOCK_BREAK_TO_NONE); + oplock_return); return NT_STATUS_OPLOCK_NOT_GRANTED; } } @@ -449,8 +467,8 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, e.oplock_level = OPLOCK_EXCLUSIVE; *oplock_granted = EXCLUSIVE_OPLOCK_RETURN; } else { - e.oplock_level = OPLOCK_NONE; - *oplock_granted = NO_OPLOCK_RETURN; + e.oplock_level = OPLOCK_LEVEL_II; + *oplock_granted = LEVEL_II_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_BATCH) { if (file.num_entries == 0) { @@ -509,10 +527,12 @@ static NTSTATUS odb_tdb_open_file_pending(struct odb_lock *lck, void *private) /* remove a opendb entry */ -static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle) +static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle, + const char **_delete_path) { struct odb_context *odb = lck->odb; struct opendb_file file; + const char *delete_path = NULL; int i; NTSTATUS status; @@ -548,7 +568,16 @@ static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle) file.num_pending = 0; file.num_entries--; - + + if (file.num_entries == 0 && file.delete_on_close) { + delete_path = talloc_strdup(lck, file.path); + NT_STATUS_HAVE_NO_MEMORY(delete_path); + } + + if (_delete_path) { + *_delete_path = delete_path; + } + return odb_push_record(lck, &file); } @@ -705,20 +734,20 @@ static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_cl people still have the file open */ static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close, - int *open_count, char **path) + DATA_BLOB *key, bool *del_on_close) { NTSTATUS status; struct opendb_file file; struct odb_lock *lck; + (*del_on_close) = false; + lck = odb_lock(odb, odb, key); NT_STATUS_HAVE_NO_MEMORY(lck); status = odb_pull_record(lck, &file); if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { talloc_free(lck); - (*del_on_close) = false; return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { @@ -727,16 +756,6 @@ static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb, } (*del_on_close) = file.delete_on_close; - if (open_count != NULL) { - (*open_count) = file.num_entries; - } - if (path != NULL) { - *path = talloc_strdup(odb, file.path); - NT_STATUS_HAVE_NO_MEMORY(*path); - if (file.num_entries == 1 && file.entries[0].delete_on_close) { - (*del_on_close) = true; - } - } talloc_free(lck); diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index a01352f60c..740a0a9d13 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -50,29 +50,10 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, */ static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h) { - int open_count; - char *path = NULL; - - if (h->name->stream_name == NULL && - pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) && - open_count == 1) { - NTSTATUS status; - status = pvfs_xattr_unlink_hook(h->pvfs, path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", - path, nt_errstr(status))); - } - if (rmdir(path) != 0) { - DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", - path, strerror(errno))); - } - } - - talloc_free(path); - if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; + const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { @@ -80,12 +61,24 @@ static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h) return 0; } - status = odb_close_file(lck, h); + status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", + DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } + if (h->name->stream_name == NULL && delete_path) { + status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", + delete_path, nt_errstr(status))); + } + if (rmdir(delete_path) != 0) { + DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", + delete_path, strerror(errno))); + } + } + talloc_free(lck); } @@ -410,9 +403,6 @@ cleanup_delete: */ static int pvfs_handle_destructor(struct pvfs_file_handle *h) { - int open_count; - char *path = NULL; - /* the write time is no longer sticky */ if (h->sticky_write_time) { NTSTATUS status; @@ -441,32 +431,10 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) h->fd = -1; } - if (h->name->stream_name == NULL && - h->open_completed && - pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) && - open_count == 1) { - NTSTATUS status; - status = pvfs_xattr_unlink_hook(h->pvfs, path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", - path, nt_errstr(status))); - } - if (unlink(path) != 0) { - DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", - path, strerror(errno))); - } else { - notify_trigger(h->pvfs->notify_context, - NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_FILE_NAME, - path); - } - } - - talloc_free(path); - if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; + const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { @@ -474,12 +442,30 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) return 0; } - status = odb_close_file(lck, h); + status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } + if (h->name->stream_name == NULL && + h->open_completed && delete_path) { + status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", + delete_path, nt_errstr(status))); + } + if (unlink(delete_path) != 0) { + DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", + delete_path, strerror(errno))); + } else { + notify_trigger(h->pvfs->notify_context, + NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + delete_path); + } + } + talloc_free(lck); } @@ -574,7 +560,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, status = pvfs_locking_key(parent, req, &locking_key); NT_STATUS_NOT_OK_RETURN(status); status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, - &del_on_close, NULL, NULL); + &del_on_close); NT_STATUS_NOT_OK_RETURN(status); if (del_on_close) { return NT_STATUS_DELETE_PENDING; @@ -1738,14 +1724,13 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, /* determine if delete on close is set on */ -bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, - int *open_count, char **path) +bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h) { NTSTATUS status; bool del_on_close; status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, - &del_on_close, open_count, path); + &del_on_close); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("WARNING: unable to determine delete on close status for open file\n")); return false; diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 8d23d707a4..6ed729541f 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -380,7 +380,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, switch (info->generic.level) { case RAW_FILEINFO_STANDARD_INFO: case RAW_FILEINFO_STANDARD_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->standard_info.out.delete_pending = 1; info->standard_info.out.nlink--; } @@ -388,7 +388,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, case RAW_FILEINFO_ALL_INFO: case RAW_FILEINFO_ALL_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->all_info.out.delete_pending = 1; info->all_info.out.nlink--; } @@ -407,7 +407,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, break; case RAW_FILEINFO_SMB2_ALL_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->all_info2.out.delete_pending = 1; info->all_info2.out.nlink--; } diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index 17c073ccab..185e35f800 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -181,6 +181,84 @@ static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx, } /* + retry an rename after a sharing violation +*/ +static void pvfs_retry_rename(struct pvfs_odb_retry *r, + struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + void *_io, + void *private_data, + enum pvfs_wait_notice reason) +{ + union smb_rename *io = talloc_get_type(_io, union smb_rename); + NTSTATUS status = NT_STATUS_INTERNAL_ERROR; + + talloc_free(r); + + switch (reason) { + case PVFS_WAIT_CANCEL: +/*TODO*/ + status = NT_STATUS_CANCELLED; + break; + case PVFS_WAIT_TIMEOUT: + /* if it timed out, then give the failure + immediately */ +/*TODO*/ + status = NT_STATUS_SHARING_VIOLATION; + break; + case PVFS_WAIT_EVENT: + + /* try the open again, which could trigger another retry setup + if it wants to, so we have to unmark the async flag so we + will know if it does a second async reply */ + req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC; + + status = pvfs_rename(ntvfs, req, io); + if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { + /* the 2nd try also replied async, so we don't send + the reply yet */ + return; + } + + /* re-mark it async, just in case someone up the chain does + paranoid checking */ + req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; + break; + } + + /* send the reply up the chain */ + req->async_states->status = status; + req->async_states->send_fn(req); +} + +/* + setup for a rename retry after a sharing violation + or a non granted oplock +*/ +static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_rename *io, + struct odb_lock *lck, + NTSTATUS status) +{ + struct pvfs_state *pvfs = ntvfs->private_data; + struct timeval end_time; + + if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + end_time = timeval_add(&req->statistics.request_time, + 0, pvfs->sharing_violation_delay); + } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) { + end_time = timeval_add(&req->statistics.request_time, + pvfs->oplock_break_timeout, 0); + } else { + return NT_STATUS_INTERNAL_ERROR; + } + + return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL, + pvfs_retry_rename); +} + +/* rename one file from a wildcard set */ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, @@ -354,8 +432,19 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs, } status = pvfs_can_rename(pvfs, req, name1, &lck); + /* + * on a sharing violation we need to retry when the file is closed by + * the other user, or after 1 second + * on a non granted oplock we need to retry when the file is closed by + * the other user, or after 30 seconds + */ + if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) || + NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) && + (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status); + } + if (!NT_STATUS_IS_OK(status)) { - talloc_free(lck); return status; } @@ -377,6 +466,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, struct pvfs_state *pvfs = ntvfs->private_data; NTSTATUS status; struct pvfs_filename *name1, *name2; + struct odb_lock *lck = NULL; switch (ren->ntrename.in.flags) { case RENAME_FLAG_RENAME: @@ -422,7 +512,18 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, return status; } - status = pvfs_can_rename(pvfs, req, name1, NULL); + status = pvfs_can_rename(pvfs, req, name1, &lck); + /* + * on a sharing violation we need to retry when the file is closed by + * the other user, or after 1 second + * on a non granted oplock we need to retry when the file is closed by + * the other user, or after 30 seconds + */ + if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) || + NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) && + (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -432,6 +533,9 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE); NT_STATUS_NOT_OK_RETURN(status); status = pvfs_do_rename(pvfs, name1, name2->full_name); + if (NT_STATUS_IS_OK(status)) { + status = odb_rename(lck, name2->full_name); + } NT_STATUS_NOT_OK_RETURN(status); break; diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 4d38dc069e..37e6351864 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -27,6 +27,7 @@ #include "auth/auth.h" #include "auth/auth_sam_reply.h" #include "dsdb/samdb/samdb.h" +#include "dsdb/common/flags.h" #include "rpc_server/samr/proto.h" #include "util/util_ldb.h" #include "libcli/auth/libcli_auth.h" @@ -76,7 +77,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca struct creds_CredentialState *creds; void *sam_ctx; struct samr_Password *mach_pwd; - uint16_t acct_flags; + uint32_t user_account_control; int num_records; struct ldb_message **msgs; NTSTATUS nt_status; @@ -113,27 +114,28 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca return NT_STATUS_INTERNAL_DB_CORRUPTION; } - acct_flags = samdb_result_acct_flags(msgs[0], - "userAccountControl"); + + user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0); - if (acct_flags & ACB_DISABLED) { + if (user_account_control & UF_ACCOUNTDISABLE) { DEBUG(1, ("Account [%s] is disabled\n", r->in.account_name)); return NT_STATUS_ACCESS_DENIED; } if (r->in.secure_channel_type == SEC_CHAN_WKSTA) { - if (!(acct_flags & ACB_WSTRUST)) { - DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", acct_flags)); + if (!(user_account_control & UF_WORKSTATION_TRUST_ACCOUNT)) { + DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", user_account_control)); return NT_STATUS_ACCESS_DENIED; } } else if (r->in.secure_channel_type == SEC_CHAN_DOMAIN) { - if (!(acct_flags & ACB_DOMTRUST)) { - DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", acct_flags)); + if (!(user_account_control & UF_INTERDOMAIN_TRUST_ACCOUNT)) { + DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", user_account_control)); + return NT_STATUS_ACCESS_DENIED; } } else if (r->in.secure_channel_type == SEC_CHAN_BDC) { - if (!(acct_flags & ACB_SVRTRUST)) { - DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", acct_flags)); + if (!(user_account_control & UF_SERVER_TRUST_ACCOUNT)) { + DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", user_account_control)); return NT_STATUS_ACCESS_DENIED; } } else { diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 760d774f2e..8193e0a882 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -56,7 +56,7 @@ #define QUERY_LHOURS(msg, field, attr) \ r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr); #define QUERY_AFLAGS(msg, field, attr) \ - r->out.info->field = samdb_result_acct_flags(msg, attr); + r->out.info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn); /* these are used to make the Set[User|Group]Info code easier to follow */ @@ -102,10 +102,25 @@ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \ } while (0) - + +#define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \ + do { \ + if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \ + return NT_STATUS_INVALID_PARAMETER; \ + } \ + } while (0) \ + +/* Set account flags, discarding flags that cannot be set with SAMR */ #define SET_AFLAGS(msg, field, attr) do { \ struct ldb_message_element *set_el; \ - if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ + if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \ + return NT_STATUS_INVALID_PARAMETER; \ + } \ + CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ + CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ + CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ + CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ + if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ @@ -1484,8 +1499,8 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, for (i=0;i<count;i++) { /* Check if a mask has been requested */ if (r->in.acct_flags - && ((samdb_result_acct_flags(res[i], - "userAccountControl") & r->in.acct_flags) == 0)) { + && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res[i], + d_state->domain_dn) & r->in.acct_flags) == 0)) { continue; } entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0); @@ -3066,7 +3081,7 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA } case 16: { - static const char * const attrs2[] = {"userAccountControl", NULL}; + static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL}; attrs = attrs2; break; } @@ -3613,7 +3628,7 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, struct ldb_message **res; int ldb_cnt, count, i; const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName", - "description", "userAccountControl", NULL }; + "description", "userAccountControl", "pwdLastSet", NULL }; struct samr_DispEntryFull *entriesFull = NULL; struct samr_DispEntryFullGroup *entriesFullGroup = NULL; struct samr_DispEntryAscii *entriesAscii = NULL; @@ -3702,8 +3717,9 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, entriesGeneral[count].rid = objectsid->sub_auths[objectsid->num_auths-1]; entriesGeneral[count].acct_flags = - samdb_result_acct_flags(res[i], - "userAccountControl"); + samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, + res[i], + d_state->domain_dn); entriesGeneral[count].account_name.string = samdb_result_string(res[i], "sAMAccountName", ""); @@ -3719,8 +3735,9 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */ entriesFull[count].acct_flags = - samdb_result_acct_flags(res[i], - "userAccountControl") | ACB_NORMAL; + samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, + res[i], + d_state->domain_dn) | ACB_NORMAL; entriesFull[count].account_name.string = samdb_result_string(res[i], "sAMAccountName", ""); @@ -3731,9 +3748,6 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, entriesFullGroup[count].idx = count + 1; entriesFullGroup[count].rid = objectsid->sub_auths[objectsid->num_auths-1]; - entriesFullGroup[count].acct_flags = - samdb_result_acct_flags(res[i], - "userAccountControl"); /* We get a "7" here for groups */ entriesFullGroup[count].acct_flags = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail index 4d850caae5..aaa11774ae 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -3,6 +3,8 @@ local.iconv.*.next_codepoint() base.delaywrite.finfo update on close base.delete.*.deltest20a base.delete.*.deltest20b +raw.oplock.*BATCH19 +raw.oplock.*BATCH20 rpc.winreg local.registry.*.security # Not implemented yet rpc.wkssvc diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index e3c47ff4a2..55935b0037 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -313,9 +313,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "server_sort", "extended_dn", "asq", - "samldb", "rdn_name", "objectclass", + "samldb", "kludge_acl", "operational"] tdb_modules_list = [ diff --git a/source4/setup/provision_self_join.ldif b/source4/setup/provision_self_join.ldif index 58669660f4..503656a9bf 100644 --- a/source4/setup/provision_self_join.ldif +++ b/source4/setup/provision_self_join.ldif @@ -8,7 +8,6 @@ localPolicyFlags: 0 primaryGroupID: 516 accountExpires: 9223372036854775807 sAMAccountName: ${NETBIOSNAME}$ -sAMAccountType: 805306369 operatingSystem: Samba operatingSystemVersion: 4.0 dNSHostName: ${DNSNAME} @@ -33,7 +32,6 @@ description: DNS Service Account userAccountControl: 514 accountExpires: 9223372036854775807 sAMAccountName: dns -sAMAccountType: 805306368 servicePrincipalName: DNS/${DNSDOMAIN} isCriticalSystemObject: TRUE sambaPassword:: ${DNSPASS_B64} diff --git a/source4/setup/provision_templates.ldif b/source4/setup/provision_templates.ldif index fafedc6966..cc0ab212cd 100644 --- a/source4/setup/provision_templates.ldif +++ b/source4/setup/provision_templates.ldif @@ -18,7 +18,7 @@ objectClass: container description: Container for SAM account templates dn: CN=TemplateUser,CN=Templates -userAccountControl: 514 +userAccountControl: 546 badPwdCount: 0 codePage: 0 countryCode: 0 @@ -29,21 +29,6 @@ pwdLastSet: 0 primaryGroupID: 513 accountExpires: -1 logonCount: 0 -sAMAccountType: 805306368 - -dn: CN=TemplateComputer,CN=Templates -userAccountControl: 4098 -badPwdCount: 0 -codePage: 0 -countryCode: 0 -badPasswordTime: 0 -lastLogoff: 0 -lastLogon: 0 -pwdLastSet: 0 -primaryGroupID: 513 -accountExpires: -1 -logonCount: 0 -sAMAccountType: 805306369 dn: CN=TemplateTrustingDomain,CN=Templates userAccountControl: 2080 @@ -56,18 +41,9 @@ lastLogon: 0 primaryGroupID: 513 accountExpires: -1 logonCount: 0 -sAMAccountType: 805306370 dn: CN=TemplateGroup,CN=Templates groupType: -2147483646 -sAMAccountType: 268435456 - -# Currently this isn't used, we don't have a way to detect it different from an incoming alias -# -# dn: CN=TemplateAlias,CN=Templates -# cn: TemplateAlias -# groupType: -2147483644 -# sAMAccountType: 268435456 dn: CN=TemplateForeignSecurityPrincipal,CN=Templates diff --git a/source4/setup/provision_users.ldif b/source4/setup/provision_users.ldif index 05fde15974..4b053d9166 100644 --- a/source4/setup/provision_users.ldif +++ b/source4/setup/provision_users.ldif @@ -44,7 +44,6 @@ objectSid: ${DOMAINSID}-502 adminCount: 1 accountExpires: 9223372036854775807 sAMAccountName: krbtgt -sAMAccountType: 805306368 servicePrincipalName: kadmin/changepw isCriticalSystemObject: TRUE sambaPassword:: ${KRBTGTPASS_B64} @@ -85,7 +84,6 @@ objectClass: group cn: Cert Publishers description: Members of this group are permitted to publish certificates to the Active Directory groupType: 2147483652 -sAMAccountType: 536870912 objectSid: ${DOMAINSID}-517 sAMAccountName: Cert Publishers isCriticalSystemObject: TRUE @@ -136,7 +134,6 @@ cn: RAS and IAS Servers description: Servers in this group can access remote access properties of users objectSid: ${DOMAINSID}-553 sAMAccountName: RAS and IAS Servers -sAMAccountType: 536870912 groupType: 2147483652 isCriticalSystemObject: TRUE @@ -151,7 +148,6 @@ member: CN=Administrator,CN=Users,${DOMAINDN} objectSid: S-1-5-32-544 adminCount: 1 sAMAccountName: Administrators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -188,7 +184,6 @@ description: Users are prevented from making accidental or intentional system-wi member: CN=Domain Users,CN=Users,${DOMAINDN} objectSid: S-1-5-32-545 sAMAccountName: Users -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -202,7 +197,6 @@ member: CN=Domain Guests,CN=Users,${DOMAINDN} member: CN=Guest,CN=Users,${DOMAINDN} objectSid: S-1-5-32-546 sAMAccountName: Guests -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -215,7 +209,6 @@ description: Members can administer domain printers objectSid: S-1-5-32-550 adminCount: 1 sAMAccountName: Print Operators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -231,7 +224,6 @@ description: Backup Operators can override security restrictions for the sole pu objectSid: S-1-5-32-551 adminCount: 1 sAMAccountName: Backup Operators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -248,7 +240,6 @@ description: Supports file replication in a domain objectSid: S-1-5-32-552 adminCount: 1 sAMAccountName: Replicator -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -260,7 +251,6 @@ cn: Remote Desktop Users description: Members in this group are granted the right to logon remotely objectSid: S-1-5-32-555 sAMAccountName: Remote Desktop Users -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -272,7 +262,6 @@ cn: Network Configuration Operators description: Members in this group can have some administrative privileges to manage configuration of networking features objectSid: S-1-5-32-556 sAMAccountName: Network Configuration Operators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -284,7 +273,6 @@ cn: Performance Monitor Users description: Members of this group have remote access to monitor this computer objectSid: S-1-5-32-558 sAMAccountName: Performance Monitor Users -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -296,7 +284,6 @@ cn: Performance Log Users description: Members of this group have remote access to schedule logging of performance counters on this computer objectSid: S-1-5-32-559 sAMAccountName: Performance Log Users -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -309,7 +296,6 @@ description: Members can administer domain servers objectSid: S-1-5-32-549 adminCount: 1 sAMAccountName: Server Operators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -328,7 +314,6 @@ description: Members can administer domain user and group accounts objectSid: S-1-5-32-548 adminCount: 1 sAMAccountName: Account Operators -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -341,7 +326,6 @@ cn: Pre-Windows 2000 Compatible Access description: A backward compatibility group which allows read access on all users and groups in the domain objectSid: S-1-5-32-554 sAMAccountName: Pre-Windows 2000 Compatible Access -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -355,7 +339,6 @@ cn: Incoming Forest Trust Builders description: Members of this group can create incoming, one-way trusts to this forest objectSid: S-1-5-32-557 sAMAccountName: Incoming Forest Trust Builders -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -367,7 +350,6 @@ cn: Windows Authorization Access Group description: Members of this group have access to the computed tokenGroupsGlobalAndUniversal attribute on User objects objectSid: S-1-5-32-560 sAMAccountName: Windows Authorization Access Group -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -379,7 +361,6 @@ cn: Terminal Server License Servers description: Terminal Server License Servers objectSid: S-1-5-32-561 sAMAccountName: Terminal Server License Servers -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE @@ -391,7 +372,6 @@ cn: Distributed COM Users description: Members are allowed to launch, activate and use Distributed COM objects on this machine. objectSid: S-1-5-32-562 sAMAccountName: Distributed COM Users -sAMAccountType: 536870912 systemFlags: 2348810240 groupType: 2147483653 isCriticalSystemObject: TRUE diff --git a/source4/torture/libnet/libnet_user.c b/source4/torture/libnet/libnet_user.c index 6ea670629e..31300a7937 100644 --- a/source4/torture/libnet/libnet_user.c +++ b/source4/torture/libnet/libnet_user.c @@ -339,12 +339,13 @@ 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), + (ACB_NORMAL | ACB_PWNOEXP), + (ACB_NORMAL) }; const char *homedir, *homedrive, *logonscript; struct timeval now; int i, testfld; - srandom((unsigned)time(NULL)); - printf("Fields to change: ["); for (i = 0; i < num_changes && i < FIELDS_NUM; i++) { @@ -382,14 +383,14 @@ static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, case home_directory: continue_if_field_set(r->in.home_directory); - homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))]; + homedir = home_dirs[random() % ARRAY_SIZE(home_dirs)]; r->in.home_directory = talloc_strdup(mem_ctx, homedir); fldname = "home_dir"; break; case home_drive: continue_if_field_set(r->in.home_drive); - homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))]; + homedrive = home_drives[random() % ARRAY_SIZE(home_drives)]; r->in.home_drive = talloc_strdup(mem_ctx, homedrive); fldname = "home_drive"; break; @@ -403,7 +404,7 @@ static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, case logon_script: continue_if_field_set(r->in.logon_script); - logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))]; + logonscript = logon_scripts[random() % ARRAY_SIZE(logon_scripts)]; r->in.logon_script = talloc_strdup(mem_ctx, logonscript); fldname = "logon_script"; break; @@ -422,6 +423,12 @@ static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, fldname = "acct_expiry"; break; + case acct_flags: + continue_if_field_set(r->in.acct_flags); + r->in.acct_flags = flags[random() % ARRAY_SIZE(flags)]; + fldname = "acct_flags"; + break; + default: fldname = "unknown_field"; } diff --git a/source4/torture/libnet/userman.c b/source4/torture/libnet/userman.c index 0d08284a9f..1d630e5ecd 100644 --- a/source4/torture/libnet/userman.c +++ b/source4/torture/libnet/userman.c @@ -189,7 +189,7 @@ static bool test_usermod(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, case acct_flags: continue_if_field_set(mod->in.change.acct_flags); - mod->in.change.acct_flags = flags[random() % (sizeof(flags)/sizeof(uint32_t))]; + mod->in.change.acct_flags = flags[random() % ARRAY_SIZE(flags)]; mod->in.change.fields |= USERMOD_FIELD_ACCT_FLAGS; fldname = "acct_flags"; break; diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index e81b634161..7ac88c0996 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -27,11 +27,19 @@ #define CHECK_VAL(v, correct) do { \ if ((v) != (correct)) { \ - torture_comment(tctx, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \ + torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \ __location__, #v, (int)v, (int)correct); \ 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", \ + __location__, #v, v?v:"NULL", correct); \ + ret = false; \ + } \ +} while (0) + #define CHECK_STATUS(tctx, status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \ @@ -123,9 +131,9 @@ static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t ti return true; } -static bool test_raw_oplock_normal(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { - const char *fname = BASEDIR "\\test_normal.dat"; + const char *fname = BASEDIR "\\test_exclusive1.dat"; NTSTATUS status; bool ret = true; union smb_open io; @@ -156,7 +164,7 @@ static bool test_raw_oplock_normal(struct torture_context *tctx, struct smbcli_s io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; - torture_comment(tctx, "open a file with a normal oplock\n"); + torture_comment(tctx, "open a file with an exclusive oplock (share mode: none)\n"); ZERO_STRUCT(break_info); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; @@ -188,6 +196,381 @@ done: return ret; } +static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_exclusive2.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_unlink unl; + uint16_t fnum=0, fnum2=0; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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; + + torture_comment(tctx, "open a file with an exclusive oplock (share mode: all)\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_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, EXCLUSIVE_OPLOCK_RETURN); + + torture_comment(tctx, "a 2nd open should cause a break to level 2\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, fnum); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + ZERO_STRUCT(break_info); + + /* now we have 2 level II oplocks... */ + torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n"); + unl.unlink.in.pattern = fname; + unl.unlink.in.attrib = 0; + status = smb_raw_unlink(cli2->tree, &unl); + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + + torture_comment(tctx, "close 1st handle\n"); + smbcli_close(cli1->tree, fnum); + + torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n"); + unl.unlink.in.pattern = fname; + unl.unlink.in.attrib = 0; + status = smb_raw_unlink(cli2->tree, &unl); + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + + torture_comment(tctx, "close 1st handle\n"); + smbcli_close(cli2->tree, fnum2); + + torture_comment(tctx, "unlink it\n"); + unl.unlink.in.pattern = fname; + unl.unlink.in.attrib = 0; + status = smb_raw_unlink(cli2->tree, &unl); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + +static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_exclusive3.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_setfileinfo sfi; + uint16_t fnum=0; + bool s3 = torture_setting_bool(tctx, "samba3", false); + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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; + + torture_comment(tctx, "open a file with an exclusive oplock (share mode: %s)\n", + s3?"all":"none"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; + if (s3) { + 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, EXCLUSIVE_OPLOCK_RETURN); + + torture_comment(tctx, "setpathinfo EOF should trigger a break to none\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfi.generic.in.file.path = fname; + sfi.end_of_file_info.in.size = 100; + + status = smb_raw_setpathinfo(cli2->tree, &sfi); + + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE); + + 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_exclusive4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_exclusive4.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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; + + torture_comment(tctx, "open with exclusive oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_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, EXCLUSIVE_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n"); + + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; + io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE; + 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, NO_OPLOCK_RETURN); + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->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_exclusive5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_exclusive5.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* 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); + + /* + 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, "open with exclusive oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_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, EXCLUSIVE_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF dispostion causes oplock break\n"); + + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; + io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; + 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.failures, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->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_exclusive6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_exclusive6_1.dat"; + const char *fname2 = BASEDIR "\\test_exclusive6_2.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_rename rn; + uint16_t fnum=0; + bool s3 = torture_setting_bool(tctx, "samba3", false); + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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 = fname1; + + /* we should use no share mode, when samba3 passes this */ + torture_comment(tctx, "open a file with an exclusive oplock (share mode: %s)\n", + s3?"all":"none"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; + if (s3) { + 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, EXCLUSIVE_OPLOCK_RETURN); + + torture_comment(tctx, "rename should not generate a break but get a sharing violation\n"); + ZERO_STRUCT(rn); + rn.generic.level = RAW_RENAME_RENAME; + rn.rename.in.pattern1 = fname1; + rn.rename.in.pattern2 = fname2; + rn.rename.in.attrib = 0; + + printf("trying rename while first file open\n"); + status = smb_raw_rename(cli2->tree, &rn); + + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 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_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_batch1.dat"; @@ -1352,6 +1735,475 @@ done: return ret; } +static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch16.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* 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); + + /* + 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, "open with batch oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + + 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); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF dispostion causes oplock break\n"); + + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; + 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.failures, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->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_batch17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_batch17_1.dat"; + const char *fname2 = BASEDIR "\\test_batch17_2.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_rename rn; + uint16_t fnum=0; + bool s3 = torture_setting_bool(tctx, "samba3", false); + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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 = fname1; + + /* we should use no share mode, when samba3 passes this */ + torture_comment(tctx, "open a file with an batch oplock (share mode: %s)\n", + s3?"all":"none"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + if (s3) { + 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, "rename should trigger a break\n"); + ZERO_STRUCT(rn); + rn.generic.level = RAW_RENAME_RENAME; + rn.rename.in.pattern1 = fname1; + rn.rename.in.pattern2 = fname2; + rn.rename.in.attrib = 0; + + printf("trying rename while first file open\n"); + status = smb_raw_rename(cli2->tree, &rn); + + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + + 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_batch18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_batch18_1.dat"; + const char *fname2 = BASEDIR "\\test_batch18_2.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_rename rn; + uint16_t fnum=0; + bool s3 = torture_setting_bool(tctx, "samba3", false); + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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 = fname1; + + /* we should use no share mode, when samba3 passes this */ + torture_comment(tctx, "open a file with an batch oplock (share mode: %s)\n", + s3?"all":"none"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + if (s3) { + 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, "ntrename should trigger a break\n"); + ZERO_STRUCT(rn); + rn.generic.level = RAW_RENAME_NTRENAME; + rn.ntrename.in.attrib = 0; + rn.ntrename.in.flags = RENAME_FLAG_RENAME; + rn.ntrename.in.old_name = fname1; + rn.ntrename.in.new_name = fname2; + printf("trying rename while first file open\n"); + status = smb_raw_rename(cli2->tree, &rn); + + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + + 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_batch19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_batch19_1.dat"; + const char *fname2 = BASEDIR "\\test_batch19_2.dat"; + const char *fname3 = BASEDIR "\\test_batch19_3.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_fileinfo qfi; + union smb_setfileinfo sfi; + uint16_t fnum=0; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT19 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + smbcli_unlink(cli1->tree, fname3); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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 = fname1; + + torture_comment(tctx, "open a file with an batch oplock (share mode: none)\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, "setpathinfo rename info should not trigger a break nor a violation\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.path = fname1; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1; + + status = smb_raw_setpathinfo(cli2->tree, &sfi); + + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2); + + torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.fnum = fnum; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1; + + status = smb_raw_setfileinfo(cli1->tree, &sfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); + + 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_batch20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_batch20_1.dat"; + const char *fname2 = BASEDIR "\\test_batch20_2.dat"; + const char *fname3 = BASEDIR "\\test_batch20_3.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_fileinfo qfi; + union smb_setfileinfo sfi; + uint16_t fnum=0,fnum2=0; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT20 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + smbcli_unlink(cli1->tree, fname3); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, 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 = fname1; + + torture_comment(tctx, "open a file with an batch oplock (share mode: all)\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, "setpathinfo rename info should not trigger a break nor a violation\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.path = fname1; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1; + + status = smb_raw_setpathinfo(cli2->tree, &sfi); + + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 0); + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2); + + /* we should use no share mode, when samba3 passes this */ + torture_comment(tctx, "open a file with the new name an batch oplock (share mode: all)\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; + io.ntcreatex.in.fname = fname2; + 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.failures, 0); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + + torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.fnum = fnum; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1; + + status = smb_raw_setfileinfo(cli1->tree, &sfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum2; + + status = smb_raw_fileinfo(cli2->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); + + smbcli_close(cli1->tree, fnum); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -1359,7 +2211,12 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, "OPLOCK"); - torture_suite_add_2smb_test(suite, "NORMAL", test_raw_oplock_normal); + torture_suite_add_2smb_test(suite, "EXCLUSIVE1", test_raw_oplock_exclusive1); + torture_suite_add_2smb_test(suite, "EXCLUSIVE2", test_raw_oplock_exclusive2); + torture_suite_add_2smb_test(suite, "EXCLUSIVE3", test_raw_oplock_exclusive3); + torture_suite_add_2smb_test(suite, "EXCLUSIVE4", test_raw_oplock_exclusive4); + torture_suite_add_2smb_test(suite, "EXCLUSIVE5", test_raw_oplock_exclusive5); + torture_suite_add_2smb_test(suite, "EXCLUSIVE6", test_raw_oplock_exclusive6); torture_suite_add_2smb_test(suite, "BATCH1", test_raw_oplock_batch1); torture_suite_add_2smb_test(suite, "BATCH2", test_raw_oplock_batch2); torture_suite_add_2smb_test(suite, "BATCH3", test_raw_oplock_batch3); @@ -1375,6 +2232,11 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH13", test_raw_oplock_batch13); torture_suite_add_2smb_test(suite, "BATCH14", test_raw_oplock_batch14); torture_suite_add_2smb_test(suite, "BATCH15", test_raw_oplock_batch15); + torture_suite_add_2smb_test(suite, "BATCH16", test_raw_oplock_batch16); + torture_suite_add_2smb_test(suite, "BATCH17", test_raw_oplock_batch17); + 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); return suite; } diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 9d6c73891b..1d6ec43399 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -416,11 +416,6 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx TEST_USERINFO_INT(21, logon_hours.bits[3], 21, logon_hours.bits[3], 4, SAMR_FIELD_LOGON_HOURS); - if (torture_setting_bool(tctx, "samba4", false)) { - printf("skipping Set Account Flag tests against Samba4\n"); - return ret; - } - TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags, (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ), (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags), @@ -1989,9 +1984,12 @@ static bool test_user_ops(struct dcerpc_pipe *p, const char *base_acct_name, enum torture_samr_choice which_ops) { char *password = NULL; + struct samr_QueryUserInfo q; + NTSTATUS status; bool ret = true; int i; + uint32_t rid; const uint32_t password_fields[] = { SAMR_FIELD_PASSWORD, SAMR_FIELD_PASSWORD2, @@ -1999,6 +1997,11 @@ static bool test_user_ops(struct dcerpc_pipe *p, 0 }; + status = test_LookupName(p, tctx, domain_handle, base_acct_name, &rid); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + } + switch (which_ops) { case TORTURE_SAMR_USER_ATTRIBUTES: if (!test_QuerySecurity(p, tctx, user_handle)) { @@ -2091,6 +2094,29 @@ static bool test_user_ops(struct dcerpc_pipe *p, ret = false; } + q.in.user_handle = user_handle; + q.in.level = 5; + + status = dcerpc_samr_QueryUserInfo(p, tctx, &q); + if (!NT_STATUS_IS_OK(status)) { + printf("QueryUserInfo level %u failed - %s\n", + q.in.level, nt_errstr(status)); + ret = false; + } else { + uint32_t expected_flags = (base_acct_flags | ACB_PWNOTREQ | ACB_DISABLED); + if ((q.out.info->info5.acct_flags) != expected_flags) { + printf("QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", + q.out.info->info5.acct_flags, + expected_flags); + ret = false; + } + if (q.out.info->info5.rid != rid) { + printf("QuerUserInfo level 5 failed, it returned %u when we expected rid of %u\n", + q.out.info->info5.rid, rid); + + } + } + break; case TORTURE_SAMR_OTHER: /* We just need the account to exist */ @@ -2667,10 +2693,14 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx q.in.level, nt_errstr(status)); ret = false; } else { - if ((q.out.info->info5.acct_flags & acct_flags) != acct_flags) { + uint32_t expected_flags = (acct_flags | ACB_PWNOTREQ | ACB_DISABLED); + if (acct_flags == ACB_NORMAL) { + expected_flags |= ACB_PW_EXPIRED; + } + if ((q.out.info->info5.acct_flags) != expected_flags) { printf("QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", q.out.info->info5.acct_flags, - acct_flags); + expected_flags); ret = false; } switch (acct_flags) { @@ -3887,7 +3917,6 @@ static bool test_GroupList(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, for (j=0; j<num_names; j++) { if (names[j] == NULL) continue; - /* Hmm. No strequal in samba4 */ if (strequal(names[j], name)) { names[j] = NULL; found = true; diff --git a/testprogs/ejs/ldap.js b/testprogs/ejs/ldap.js index 090f93b6ca..c30f29e249 100755 --- a/testprogs/ejs/ldap.js +++ b/testprogs/ejs/ldap.js @@ -29,14 +29,19 @@ function basic_tests(ldb, gc_ldb, base_dn, configuration_dn, schema_dn) { println("Running basic tests"); + ldb.del("cn=ldaptestcomputer,cn=computers," + base_dn); + ldb.del("cn=ldaptestcomputer3,cn=computers," + base_dn); + ldb.del("cn=ldaptest2computer,cn=computers," + base_dn); ldb.del("cn=ldaptestuser,cn=users," + base_dn); ldb.del("cn=ldaptestuser2,cn=users," + base_dn); ldb.del("cn=ldaptestuser3,cn=users," + base_dn); ldb.del("cn=ldaptestuser4,cn=users," + base_dn); ldb.del("cn=ldaptestuser5,cn=users," + base_dn); ldb.del("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn); + ldb.del("cn=ldaptestuser7,cn=users," + base_dn); ldb.del("CN=ldaptestcontainer2," + base_dn); ldb.del("cn=ldaptestgroup,cn=users," + base_dn); + ldb.del("cn=ldaptestgroup2,cn=users," + base_dn); println("Testing group add with invalid member"); var ok = ldb.add(" @@ -127,7 +132,7 @@ displayname: ldap testy ok = ldb.del("cn=ldaptest2computer,cn=computers," + base_dn); if (ok.error != 0) { println(ok.errstr); - assert(ok.error == 0); + // assert(ok.error == 0); } ok = ldb.add(" dn: cn=ldaptest2computer,cn=computers," + base_dn + " @@ -142,6 +147,113 @@ displayname: ldap testy } } + var ok = ldb.add(" +dn: cn=ldaptestcomputer3,cn=computers," + base_dn + " +objectClass: computer +cn: LDAPtest2COMPUTER +"); + if (ok.error != 34) { + println("Did not reject invalid RDN compared with DN: " + ok.errstr); + assert(ok.error == 34); + } + + var ok = ldb.add(" +dn: cn=ldaptestcomputer3,cn=computers," + base_dn + " +objectClass: computer +cn: LDAPtestCOMPUTER3 +sAMAccountType: 805306368 +"); + + if (ok.error != 53) { + println("Did not reject invalid 'sAMAccountType: 805306368': " + ok.errstr); + assert(ok.error == 53); + } + + var ok = ldb.add(" +dn: cn=ldaptestcomputer3,cn=computers," + base_dn + " +objectClass: computer +cn: LDAPtestCOMPUTER3 +userAccountControl: 0 +"); + + if (ok.error != 53) { + println("Did not reject invalid 'userAccountControl: 0': " + ok.errstr); + assert(ok.error == 53); + } + + var ok = ldb.add(" +dn: cn=ldaptestuser7,cn=users," + base_dn + " +objectClass: user +cn: LDAPtestuser7 +userAccountControl: 0 +"); + + if (ok.error != 53) { + println("Did not reject invalid 'userAccountControl: 0': " + ok.errstr); + assert(ok.error == 53); + } + + var ok = ldb.add(" +dn: cn=ldaptestuser7,cn=users," + base_dn + " +objectClass: user +cn: LDAPtestuser7 +userAccountControl: 2 +"); + + if (ok.error != 0) { + println("Did not accept 'userAccountControl: 2': " + ok.errstr); + assert(ok.error == 0); + } + + ldb.del("cn=ldaptestuser7,cn=users," + base_dn); + + var ok = ldb.add(" +dn: cn=ldaptestcomputer3,cn=computers," + base_dn + " +objectclass: computer +cN: LDAPtestCOMPUTER3 +"); + if (ok.error != 0) { + ok = ldb.del("cn=ldaptestcomputer3,cn=computers," + base_dn); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + ok = ldb.add(" +dn: cn=ldaptestcomputer3,cn=computers," + base_dn + " +objectClass: computer +cn: LDAPtestCOMPUTER3 +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + } + + println("Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))"); + var res = ldb.search("(&(cn=ldaptestcomputer3)(objectClass=user))"); + if (res.error != 0 || res.msgs.length != 1) { + println("Could not find (&(cn=ldaptestcomputer3)(objectClass=user))"); + assert(res.error == 0); + assert(res.msgs.length == 1); + } + + assert(res.msgs[0].dn == ("CN=ldaptestcomputer3,CN=Computers," + base_dn)); + assert(res.msgs[0].cn == "ldaptestcomputer3"); + assert(res.msgs[0].name == "ldaptestcomputer3"); + assert(res.msgs[0].objectClass[0] == "top"); + assert(res.msgs[0].objectClass[1] == "person"); + assert(res.msgs[0].objectClass[2] == "organizationalPerson"); + assert(res.msgs[0].objectClass[3] == "user"); + assert(res.msgs[0].objectClass[4] == "computer"); + assert(res.msgs[0].objectGUID != undefined); + assert(res.msgs[0].whenCreated != undefined); + assert(res.msgs[0].objectCategory == ("CN=Computer,CN=Schema,CN=Configuration," + base_dn)); + assert(res.msgs[0].primaryGroupID == 513); + assert(res.msgs[0].sAMAccountType == 805306368); + assert(res.msgs[0].userAccountControl == 546); + + ldb.del(res.msgs[0].dn); + println("Testing attribute or value exists behaviour"); ok = ldb.modify(" dn: cn=ldaptest2computer,cn=computers," + base_dn + " @@ -374,6 +486,13 @@ sn: ldap user2 assert(res.msgs.length == 2); } + var res = ldb.search("(&(anr=testy ldap)(objectClass=user))"); + if (res.error != 0 || res.msgs.length != 2) { + println("Found only " + res.msgs.length + " for (&(anr=\"testy ldap\")(objectClass=user))"); + assert(res.error == 0); + assert(res.msgs.length == 2); + } + // Testing ldb.search for (&(anr=ldap)(objectClass=user)) var res = ldb.search("(&(anr=ldap)(objectClass=user))"); if (res.error != 0 || res.msgs.length != 4) { @@ -547,6 +666,38 @@ member: cn=ldaptestuser3,cn=users," + base_dn + " assert(res.msgs[0].cn == "ldaptestUSER3"); assert(res.msgs[0].name == "ldaptestUSER3"); + println("Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"); + var res = ldb.search("(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"); + if (res.error != 0 || res.msgs.length != 1) { + println("Could not find (&(cn=ldaptestuser3)(objectClass=user))"); + assert(res.error == 0); + assert(res.msgs.length == 1); + } + + assert(res.msgs[0].dn == ("CN=ldaptestUSER3,CN=Users," + base_dn)); + assert(res.msgs[0].cn == "ldaptestUSER3"); + assert(res.msgs[0].name == "ldaptestUSER3"); + + println("Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"); + var res = ldb.search("(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"); + if (res.error != 0 || res.msgs.length != 1) { + println("Could not find (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"); + assert(res.error == 0); + assert(res.msgs.length == 1); + } + + assert(res.msgs[0].dn == ("CN=ldaptestUSER3,CN=Users," + base_dn)); + assert(res.msgs[0].cn == "ldaptestUSER3"); + assert(res.msgs[0].name == "ldaptestUSER3"); + + println("Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"); + var res = ldb.search("(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"); + if (res.error != 0 || res.msgs.length != 0) { + println("Should not find (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"); + assert(res.error == 0); + assert(res.msgs.length == 0); + } + // This is a Samba special, and does not exist in real AD // println("Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")"); // var res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")"); @@ -840,7 +991,7 @@ objectClass: user assert(res.msgs[0].whenCreated != undefined); assert(res.msgs[0].objectCategory == ("CN=Person,CN=Schema,CN=Configuration," + base_dn)); assert(res.msgs[0].sAMAccountType == 805306368); -// assert(res[0].userAccountControl == 546); + assert(res.msgs[0].userAccountControl == 546); assert(res.msgs[0].memberOf[0] == ("CN=ldaptestgroup2,CN=Users," + base_dn)); assert(res.msgs[0].memberOf.length == 1); @@ -901,7 +1052,7 @@ objectClass: user println("Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"); var res = ldb.search("(&(cn=ldaptestcomputer)(objectClass=user))"); if (res.error != 0 || res.msgs.length != 1) { - println("Could not find (&(cn=ldaptestuser)(objectClass=user))"); + println("Could not find (&(cn=ldaptestcomputer)(objectClass=user))"); assert(res.error == 0); assert(res.msgs.length == 1); } @@ -916,12 +1067,9 @@ objectClass: user assert(res.msgs[0].objectClass[4] == "computer"); assert(res.msgs[0].objectGUID != undefined); assert(res.msgs[0].whenCreated != undefined); - assert(res.msgs[0].objectCategory == ("CN=Computer,CN=Schema,CN=Configuration," + base_dn)); - assert(res.msgs[0].primaryGroupID == 513); -// assert(res.msgs[0].sAMAccountType == 805306368); -// assert(res.msgs[0].userAccountControl == 546); - assert(res.msgs[0].memberOf[0] == ("CN=ldaptestgroup2,CN=Users," + base_dn)); - assert(res.msgs[0].memberOf.length == 1); + assert(res.msgs[0].objectCategory == "cn=Computer,cn=Schema,cn=Configuration," + base_dn); + assert(res.msgs[0].sAMAccountType == 805306368); + assert(res.msgs[0].userAccountControl == 546); println("Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))"); var res2 = ldb.search("(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))"); @@ -1023,7 +1171,7 @@ objectClass: user assert(res.msgs[0].whenCreated != undefined); assert(res.msgs[0].objectCategory == "cn=Computer,cn=Schema,cn=Configuration," + base_dn); assert(res.msgs[0].sAMAccountType == 805306369); -// assert(res.msgs[0].userAccountControl == 4098); + assert(res.msgs[0].userAccountControl == 4096); ok = ldb.del(res.msgs[0].dn); |