X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Ftorture%2Frpc%2Fsamr.c;h=c3076ebdf0ce86068a5634278409340b08a8d724;hb=16b2118b4369f8204d86d5ad2eb117837da26789;hp=9c867fd5e41e71c125e9332e027d3fa253a2d0ac;hpb=32add69632ed4a2b877043c8df1185008516c299;p=samba.git diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 9c867fd5e41..f7d6a93bb39 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -1,36 +1,43 @@ -/* +/* Unix SMB/CIFS implementation. test suite for samr rpc operations Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Bartlett 2003 - + Copyright (C) Guenther Deschner 2008-2010 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "torture/torture.h" +#include #include "system/time.h" #include "librpc/gen_ndr/lsa.h" #include "librpc/gen_ndr/ndr_netlogon.h" #include "librpc/gen_ndr/ndr_netlogon_c.h" #include "librpc/gen_ndr/ndr_samr_c.h" +#include "librpc/gen_ndr/ndr_lsa_c.h" #include "../lib/crypto/crypto.h" #include "libcli/auth/libcli_auth.h" #include "libcli/security/security.h" -#include "torture/rpc/rpc.h" +#include "torture/rpc/torture_rpc.h" #include "param/param.h" +#include "auth/gensec/gensec.h" +#include "auth/gensec/schannel.h" +#include "auth/gensec/gensec_proto.h" +#include "../libcli/auth/schannel.h" #include @@ -44,21 +51,38 @@ enum torture_samr_choice { TORTURE_SAMR_PASSWORDS, TORTURE_SAMR_PASSWORDS_PWDLASTSET, + TORTURE_SAMR_PASSWORDS_BADPWDCOUNT, + TORTURE_SAMR_PASSWORDS_LOCKOUT, TORTURE_SAMR_USER_ATTRIBUTES, - TORTURE_SAMR_OTHER + TORTURE_SAMR_USER_PRIVILEGES, + TORTURE_SAMR_OTHER, + TORTURE_SAMR_MANY_ACCOUNTS, + TORTURE_SAMR_MANY_GROUPS, + TORTURE_SAMR_MANY_ALIASES }; -static bool test_QueryUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +struct torture_samr_context { + struct policy_handle handle; + struct cli_credentials *machine_credentials; + enum torture_samr_choice choice; + uint32_t num_objects_large_dc; +}; + +static bool test_QueryUserInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle); -static bool test_QueryUserInfo2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_QueryUserInfo2(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle); -static bool test_QueryAliasInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle); +static bool test_QueryAliasInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle); -static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - const char *acct_name, +static bool test_ChangePassword(struct dcerpc_pipe *p, + struct torture_context *tctx, + const char *acct_name, struct policy_handle *domain_handle, char **password); static void init_lsa_String(struct lsa_String *string, const char *s) @@ -66,6 +90,11 @@ static void init_lsa_String(struct lsa_String *string, const char *s) string->string = s; } +static void init_lsa_StringLarge(struct lsa_StringLarge *string, const char *s) +{ + string->string = s; +} + static void init_lsa_BinaryString(struct lsa_BinaryString *string, const char *s, uint32_t length) { string->length = length; @@ -73,25 +102,26 @@ static void init_lsa_BinaryString(struct lsa_BinaryString *string, const char *s string->array = (uint16_t *)discard_const(s); } -bool test_samr_handle_Close(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle) +bool test_samr_handle_Close(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_Close r; r.in.handle = handle; r.out.handle = handle; - status = dcerpc_samr_Close(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "Close"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Close_r(b, tctx, &r), + "Close failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "Close failed"); return true; } -static bool test_Shutdown(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle) +static bool test_Shutdown(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_Shutdown r; if (!torture_setting_bool(tctx, "dangerous", false)) { @@ -101,18 +131,19 @@ static bool test_Shutdown(struct dcerpc_pipe *p, struct torture_context *tctx, r.in.connect_handle = handle; - torture_comment(tctx, "testing samr_Shutdown\n"); + torture_comment(tctx, "Testing samr_Shutdown\n"); - status = dcerpc_samr_Shutdown(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "samr_Shutdown"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Shutdown_r(b, tctx, &r), + "Shutdown failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "Shutdown failed"); return true; } -static bool test_SetDsrmPassword(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_SetDsrmPassword(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_SetDsrmPassword r; struct lsa_String string; struct samr_Password hash; @@ -129,20 +160,20 @@ static bool test_SetDsrmPassword(struct dcerpc_pipe *p, struct torture_context * r.in.unknown = 0; r.in.hash = &hash; - torture_comment(tctx, "testing samr_SetDsrmPassword\n"); + torture_comment(tctx, "Testing samr_SetDsrmPassword\n"); - status = dcerpc_samr_SetDsrmPassword(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED, "samr_SetDsrmPassword"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDsrmPassword_r(b, tctx, &r), + "SetDsrmPassword failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_SUPPORTED, "SetDsrmPassword failed"); return true; } -static bool test_QuerySecurity(struct dcerpc_pipe *p, - struct torture_context *tctx, +static bool test_QuerySecurity(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QuerySecurity r; struct samr_SetSecurity s; struct sec_desc_buf *sdbuf = NULL; @@ -151,8 +182,9 @@ static bool test_QuerySecurity(struct dcerpc_pipe *p, r.in.sec_info = 7; r.out.sdbuf = &sdbuf; - status = dcerpc_samr_QuerySecurity(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "QuerySecurity"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &r), + "QuerySecurity failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "QuerySecurity failed"); torture_assert(tctx, sdbuf != NULL, "sdbuf is NULL"); @@ -164,21 +196,22 @@ static bool test_QuerySecurity(struct dcerpc_pipe *p, torture_skip(tctx, "skipping SetSecurity test against Samba4\n"); } - status = dcerpc_samr_SetSecurity(p, tctx, &s); - torture_assert_ntstatus_ok(tctx, status, "SetSecurity"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetSecurity_r(b, tctx, &s), + "SetSecurity failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "SetSecurity failed"); - status = dcerpc_samr_QuerySecurity(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "QuerySecurity"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &r), + "QuerySecurity failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "QuerySecurity failed"); return true; } -static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_SetUserInfo(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, uint32_t base_acct_flags, const char *base_account_name) { - NTSTATUS status; struct samr_SetUserInfo s; struct samr_SetUserInfo2 s2; struct samr_QueryUserInfo q; @@ -189,9 +222,12 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx const char *test_account_name; uint32_t user_extra_flags = 0; - if (base_acct_flags == ACB_NORMAL) { - /* When created, accounts are expired by default */ - user_extra_flags = ACB_PW_EXPIRED; + + if (!torture_setting_bool(tctx, "samba3", false)) { + if (base_acct_flags == ACB_NORMAL) { + /* When created, accounts are expired by default */ + user_extra_flags = ACB_PW_EXPIRED; + } } s.in.user_handle = handle; @@ -205,10 +241,11 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx q0 = q; #define TESTCALL(call, r) \ - status = dcerpc_samr_ ##call(p, tctx, &r); \ - if (!NT_STATUS_IS_OK(status)) { \ + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ ##call## _r(b, tctx, &r),\ + #call " failed"); \ + if (!NT_STATUS_IS_OK(r.out.result)) { \ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \ - r.in.level, nt_errstr(status), __location__); \ + r.in.level, nt_errstr(r.out.result), __location__); \ ret = false; \ break; \ } @@ -323,7 +360,7 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx TEST_USERINFO_STRING(2, comment, 1, comment, "xx2-1 comment", 0); TEST_USERINFO_STRING(2, comment, 21, comment, "xx2-21 comment", 0); - TEST_USERINFO_STRING(21, comment, 21, comment, "xx21-21 comment", + TEST_USERINFO_STRING(21, comment, 21, comment, "xx21-21 comment", SAMR_FIELD_COMMENT); test_account_name = talloc_asprintf(tctx, "%sxx7-1", base_account_name); @@ -339,7 +376,7 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx test_account_name = talloc_asprintf(tctx, "%sxx7-21", base_account_name); TEST_USERINFO_STRING(7, account_name, 21, account_name, base_account_name, 0); test_account_name = base_account_name; - TEST_USERINFO_STRING(21, account_name, 21, account_name, base_account_name, + TEST_USERINFO_STRING(21, account_name, 21, account_name, base_account_name, SAMR_FIELD_ACCOUNT_NAME); TEST_USERINFO_STRING(6, full_name, 1, full_name, "xx6-1 full_name", 0); @@ -349,7 +386,7 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx TEST_USERINFO_STRING(6, full_name, 8, full_name, "xx6-8 full_name", 0); TEST_USERINFO_STRING(6, full_name, 21, full_name, "xx6-21 full_name", 0); TEST_USERINFO_STRING(8, full_name, 21, full_name, "xx8-21 full_name", 0); - TEST_USERINFO_STRING(21, full_name, 21, full_name, "xx21-21 full_name", + TEST_USERINFO_STRING(21, full_name, 21, full_name, "xx21-21 full_name", SAMR_FIELD_FULL_NAME); TEST_USERINFO_STRING(6, full_name, 1, full_name, "", 0); @@ -359,19 +396,19 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx TEST_USERINFO_STRING(6, full_name, 8, full_name, "", 0); TEST_USERINFO_STRING(6, full_name, 21, full_name, "", 0); TEST_USERINFO_STRING(8, full_name, 21, full_name, "", 0); - TEST_USERINFO_STRING(21, full_name, 21, full_name, "", + TEST_USERINFO_STRING(21, full_name, 21, full_name, "", SAMR_FIELD_FULL_NAME); TEST_USERINFO_STRING(11, logon_script, 3, logon_script, "xx11-3 logon_script", 0); TEST_USERINFO_STRING(11, logon_script, 5, logon_script, "xx11-5 logon_script", 0); TEST_USERINFO_STRING(11, logon_script, 21, logon_script, "xx11-21 logon_script", 0); - TEST_USERINFO_STRING(21, logon_script, 21, logon_script, "xx21-21 logon_script", + TEST_USERINFO_STRING(21, logon_script, 21, logon_script, "xx21-21 logon_script", SAMR_FIELD_LOGON_SCRIPT); TEST_USERINFO_STRING(12, profile_path, 3, profile_path, "xx12-3 profile_path", 0); TEST_USERINFO_STRING(12, profile_path, 5, profile_path, "xx12-5 profile_path", 0); TEST_USERINFO_STRING(12, profile_path, 21, profile_path, "xx12-21 profile_path", 0); - TEST_USERINFO_STRING(21, profile_path, 21, profile_path, "xx21-21 profile_path", + TEST_USERINFO_STRING(21, profile_path, 21, profile_path, "xx21-21 profile_path", SAMR_FIELD_PROFILE_PATH); TEST_USERINFO_STRING(10, home_directory, 3, home_directory, "xx10-3 home_directory", 0); @@ -389,23 +426,23 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx SAMR_FIELD_HOME_DRIVE); TEST_USERINFO_STRING(21, home_drive, 10, home_drive, "xx21-10 home_drive", SAMR_FIELD_HOME_DRIVE); - + TEST_USERINFO_STRING(13, description, 1, description, "xx13-1 description", 0); TEST_USERINFO_STRING(13, description, 5, description, "xx13-5 description", 0); TEST_USERINFO_STRING(13, description, 21, description, "xx13-21 description", 0); - TEST_USERINFO_STRING(21, description, 21, description, "xx21-21 description", + TEST_USERINFO_STRING(21, description, 21, description, "xx21-21 description", SAMR_FIELD_DESCRIPTION); TEST_USERINFO_STRING(14, workstations, 3, workstations, "14workstation3", 0); TEST_USERINFO_STRING(14, workstations, 5, workstations, "14workstation4", 0); TEST_USERINFO_STRING(14, workstations, 21, workstations, "14workstation21", 0); - TEST_USERINFO_STRING(21, workstations, 21, workstations, "21workstation21", + TEST_USERINFO_STRING(21, workstations, 21, workstations, "21workstation21", SAMR_FIELD_WORKSTATIONS); - TEST_USERINFO_STRING(21, workstations, 3, workstations, "21workstation3", + TEST_USERINFO_STRING(21, workstations, 3, workstations, "21workstation3", SAMR_FIELD_WORKSTATIONS); - TEST_USERINFO_STRING(21, workstations, 5, workstations, "21workstation5", + TEST_USERINFO_STRING(21, workstations, 5, workstations, "21workstation5", SAMR_FIELD_WORKSTATIONS); - TEST_USERINFO_STRING(21, workstations, 14, workstations, "21workstation14", + TEST_USERINFO_STRING(21, workstations, 14, workstations, "21workstation14", SAMR_FIELD_WORKSTATIONS); TEST_USERINFO_BINARYSTRING(20, parameters, 21, parameters, "xx20-21 parameters", 0); @@ -420,90 +457,111 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx TEST_USERINFO_BINARYSTRING(21, parameters, 20, parameters, "", SAMR_FIELD_PARAMETERS); - TEST_USERINFO_INT(2, country_code, 2, country_code, __LINE__, 0); - TEST_USERINFO_INT(2, country_code, 21, country_code, __LINE__, 0); - TEST_USERINFO_INT(21, country_code, 21, country_code, __LINE__, - SAMR_FIELD_COUNTRY_CODE); - TEST_USERINFO_INT(21, country_code, 2, country_code, __LINE__, - SAMR_FIELD_COUNTRY_CODE); - - TEST_USERINFO_INT(2, code_page, 21, code_page, __LINE__, 0); - TEST_USERINFO_INT(21, code_page, 21, code_page, __LINE__, - SAMR_FIELD_CODE_PAGE); - TEST_USERINFO_INT(21, code_page, 2, code_page, __LINE__, - SAMR_FIELD_CODE_PAGE); - - TEST_USERINFO_INT(17, acct_expiry, 21, acct_expiry, __LINE__, 0); - TEST_USERINFO_INT(17, acct_expiry, 5, acct_expiry, __LINE__, 0); - TEST_USERINFO_INT(21, acct_expiry, 21, acct_expiry, __LINE__, - SAMR_FIELD_ACCT_EXPIRY); - TEST_USERINFO_INT(21, acct_expiry, 5, acct_expiry, __LINE__, - SAMR_FIELD_ACCT_EXPIRY); - TEST_USERINFO_INT(21, acct_expiry, 17, acct_expiry, __LINE__, - SAMR_FIELD_ACCT_EXPIRY); + /* Samba 3 cannot store country_code and code_page atm. - gd */ + if (!torture_setting_bool(tctx, "samba3", false)) { + TEST_USERINFO_INT(2, country_code, 2, country_code, __LINE__, 0); + TEST_USERINFO_INT(2, country_code, 21, country_code, __LINE__, 0); + TEST_USERINFO_INT(21, country_code, 21, country_code, __LINE__, + SAMR_FIELD_COUNTRY_CODE); + TEST_USERINFO_INT(21, country_code, 2, country_code, __LINE__, + SAMR_FIELD_COUNTRY_CODE); + + TEST_USERINFO_INT(2, code_page, 21, code_page, __LINE__, 0); + TEST_USERINFO_INT(21, code_page, 21, code_page, __LINE__, + SAMR_FIELD_CODE_PAGE); + TEST_USERINFO_INT(21, code_page, 2, code_page, __LINE__, + SAMR_FIELD_CODE_PAGE); + } + + if (!torture_setting_bool(tctx, "samba3", false)) { + TEST_USERINFO_INT(17, acct_expiry, 21, acct_expiry, __LINE__, 0); + TEST_USERINFO_INT(17, acct_expiry, 5, acct_expiry, __LINE__, 0); + TEST_USERINFO_INT(21, acct_expiry, 21, acct_expiry, __LINE__, + SAMR_FIELD_ACCT_EXPIRY); + TEST_USERINFO_INT(21, acct_expiry, 5, acct_expiry, __LINE__, + SAMR_FIELD_ACCT_EXPIRY); + TEST_USERINFO_INT(21, acct_expiry, 17, acct_expiry, __LINE__, + SAMR_FIELD_ACCT_EXPIRY); + } else { + /* Samba 3 can only store seconds / time_t in passdb - gd */ + NTTIME nt; + unix_to_nt_time(&nt, time(NULL) + __LINE__); + TEST_USERINFO_INT(17, acct_expiry, 21, acct_expiry, nt, 0); + unix_to_nt_time(&nt, time(NULL) + __LINE__); + TEST_USERINFO_INT(17, acct_expiry, 5, acct_expiry, nt, 0); + unix_to_nt_time(&nt, time(NULL) + __LINE__); + TEST_USERINFO_INT(21, acct_expiry, 21, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY); + unix_to_nt_time(&nt, time(NULL) + __LINE__); + TEST_USERINFO_INT(21, acct_expiry, 5, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY); + unix_to_nt_time(&nt, time(NULL) + __LINE__); + TEST_USERINFO_INT(21, acct_expiry, 17, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY); + } TEST_USERINFO_INT(4, logon_hours.bits[3], 3, logon_hours.bits[3], 1, 0); TEST_USERINFO_INT(4, logon_hours.bits[3], 5, logon_hours.bits[3], 2, 0); TEST_USERINFO_INT(4, logon_hours.bits[3], 21, logon_hours.bits[3], 3, 0); - TEST_USERINFO_INT(21, logon_hours.bits[3], 21, logon_hours.bits[3], 4, + TEST_USERINFO_INT(21, logon_hours.bits[3], 21, logon_hours.bits[3], 4, SAMR_FIELD_LOGON_HOURS); - 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), + 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), 0); - TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags, - (base_acct_flags | ACB_DISABLED), - (base_acct_flags | ACB_DISABLED | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags, + (base_acct_flags | ACB_DISABLED), + (base_acct_flags | ACB_DISABLED | user_extra_flags), 0); - + /* Setting PWNOEXP clears the magic ACB_PW_EXPIRED flag */ - TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP), - (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP), + TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP), + (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP), 0); - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ), - (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ), + (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags), 0); /* The 'autolock' flag doesn't stick - check this */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_AUTOLOCK), - (base_acct_flags | ACB_DISABLED | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_AUTOLOCK), + (base_acct_flags | ACB_DISABLED | user_extra_flags), 0); #if 0 /* Removing the 'disabled' flag doesn't stick - check this */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags), - (base_acct_flags | ACB_DISABLED | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags), + (base_acct_flags | ACB_DISABLED | user_extra_flags), 0); #endif + + /* Samba3 cannot store these atm */ + if (!torture_setting_bool(tctx, "samba3", false)) { /* The 'store plaintext' flag does stick */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED), - (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED), + (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED | user_extra_flags), 0); /* The 'use DES' flag does stick */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY), - (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY), + (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY | user_extra_flags), 0); /* The 'don't require kerberos pre-authentication flag does stick */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH), - (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH), + (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH | user_extra_flags), 0); /* The 'no kerberos PAC required' flag sticks */ - TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD), - (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD | user_extra_flags), + TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD), + (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD | user_extra_flags), 0); - - TEST_USERINFO_INT_EXP(21, acct_flags, 21, acct_flags, - (base_acct_flags | ACB_DISABLED), - (base_acct_flags | ACB_DISABLED | user_extra_flags), + } + TEST_USERINFO_INT_EXP(21, acct_flags, 21, acct_flags, + (base_acct_flags | ACB_DISABLED), + (base_acct_flags | ACB_DISABLED | user_extra_flags), SAMR_FIELD_ACCT_FLAGS); #if 0 @@ -523,8 +581,8 @@ static bool test_SetUserInfo(struct dcerpc_pipe *p, struct torture_context *tctx */ static char *samr_rand_pass_silent(TALLOC_CTX *mem_ctx, int min_len) { - size_t len = MAX(8, min_len) + (random() % 6); - char *s = generate_random_str(mem_ctx, len); + size_t len = MAX(8, min_len); + char *s = generate_random_password(mem_ctx, len, len+6); return s; } @@ -559,7 +617,7 @@ static DATA_BLOB samr_very_rand_pass(TALLOC_CTX *mem_ctx, int len) */ static char *samr_rand_pass_fixed_len(TALLOC_CTX *mem_ctx, int len) { - char *s = generate_random_str(mem_ctx, len); + char *s = generate_random_password(mem_ctx, len, len); printf("Generated password '%s'\n", s); return s; } @@ -573,14 +631,16 @@ static bool test_SetUserPass(struct dcerpc_pipe *p, struct torture_context *tctx bool ret = true; DATA_BLOB session_key; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; int policy_min_pw_len = 0; pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); @@ -594,7 +654,7 @@ static bool test_SetUserPass(struct dcerpc_pipe *p, struct torture_context *tctx status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -603,10 +663,11 @@ static bool test_SetUserPass(struct dcerpc_pipe *p, struct torture_context *tctx torture_comment(tctx, "Testing SetUserInfo level 24 (set password)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -625,6 +686,7 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t union samr_UserInfo u; bool ret = true; DATA_BLOB session_key; + struct dcerpc_binding_handle *b = p->binding_handle; char *newpass; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; @@ -632,8 +694,9 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); @@ -650,7 +713,7 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -659,10 +722,11 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 23 (set password)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -672,7 +736,7 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -683,10 +747,11 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 23 (set password) with wrong password\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } @@ -695,7 +760,7 @@ static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *t static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, bool makeshort, + struct policy_handle *handle, bool makeshort, char **password) { NTSTATUS status; @@ -706,6 +771,7 @@ static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tc DATA_BLOB confounded_session_key = data_blob_talloc(tctx, NULL, 16); uint8_t confounder[16]; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct MD5Context ctx; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; @@ -713,8 +779,9 @@ static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tc pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } if (makeshort && policy_min_pw_len) { @@ -732,7 +799,7 @@ static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tc status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -749,10 +816,11 @@ static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tc torture_comment(tctx, "Testing SetUserInfo level 26 (set password ex)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -766,10 +834,11 @@ static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tc torture_comment(tctx, "Testing SetUserInfo level 26 (set password ex) with wrong session key\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("SetUserInfo level %u should have failed with WRONG_PASSWORD: %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "SetUserInfo level %u should have failed with WRONG_PASSWORD: %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -791,14 +860,16 @@ static bool test_SetUserPass_25(struct dcerpc_pipe *p, struct torture_context *t struct MD5Context ctx; uint8_t confounder[16]; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; int policy_min_pw_len = 0; pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); @@ -815,7 +886,7 @@ static bool test_SetUserPass_25(struct dcerpc_pipe *p, struct torture_context *t status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -832,10 +903,11 @@ static bool test_SetUserPass_25(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -849,10 +921,11 @@ static bool test_SetUserPass_25(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex) with wrong session key\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } @@ -868,6 +941,7 @@ static bool test_SetUserPass_18(struct dcerpc_pipe *p, struct torture_context *t bool ret = true; DATA_BLOB session_key; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; int policy_min_pw_len = 0; @@ -876,8 +950,9 @@ static bool test_SetUserPass_18(struct dcerpc_pipe *p, struct torture_context *t pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); @@ -896,7 +971,7 @@ static bool test_SetUserPass_18(struct dcerpc_pipe *p, struct torture_context *t status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -918,10 +993,11 @@ static bool test_SetUserPass_18(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 18 (set password hash)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -940,6 +1016,7 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t bool ret = true; DATA_BLOB session_key; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; int policy_min_pw_len = 0; @@ -948,8 +1025,9 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); @@ -981,7 +1059,7 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -1006,10 +1084,11 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t torture_comment(tctx, "Testing SetUserInfo level 21 (set password hash)\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } else { *password = newpass; @@ -1020,11 +1099,11 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t u.info21.nt_owf_password.length++; - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - - if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_warning(tctx, "SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } } @@ -1033,11 +1112,11 @@ static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *t u.info21.lm_owf_password.length++; - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - - if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_warning(tctx, "SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } } @@ -1065,6 +1144,7 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, struct MD5Context ctx; uint8_t confounder[16]; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; int policy_min_pw_len = 0; @@ -1074,8 +1154,9 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, pwp.in.user_handle = handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass_silent(tctx, policy_min_pw_len); @@ -1091,7 +1172,7 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, } if (fields_present & SAMR_FIELD_COMMENT) { - comment = talloc_asprintf(tctx, "comment: %ld\n", time(NULL)); + comment = talloc_asprintf(tctx, "comment: %ld\n", (long int) time(NULL)); } ZERO_STRUCT(u); @@ -1164,7 +1245,7 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -1229,9 +1310,13 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, } if (use_setinfo2) { - status = dcerpc_samr_SetUserInfo2(p, tctx, &s2); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo2_r(b, tctx, &s2), + "SetUserInfo2 failed"); + status = s2.out.result; } else { - status = dcerpc_samr_SetUserInfo(p, tctx, &s); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + status = s.out.result; } if (!NT_STATUS_IS_OK(status)) { @@ -1258,7 +1343,7 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, } if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo%s level %u failed - %s\n", + torture_warning(tctx, "SetUserInfo%s level %u failed - %s\n", use_setinfo2 ? "2":"", level, nt_errstr(status)); ret = false; } else { @@ -1268,10 +1353,10 @@ static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p, return ret; } -static bool test_SetAliasInfo(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle) +static bool test_SetAliasInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_SetAliasInfo r; struct samr_QueryAliasInfo q; union samr_AliasInfo *info; @@ -1293,13 +1378,14 @@ static bool test_SetAliasInfo(struct dcerpc_pipe *p, struct torture_context *tct case ALIASINFONAME: init_lsa_String(&r.in.info->name,TEST_ALIASNAME); break; case ALIASINFODESCRIPTION: init_lsa_String(&r.in.info->description, "Test Description, should test I18N as well"); break; - case ALIASINFOALL: printf("ALIASINFOALL ignored\n"); break; + case ALIASINFOALL: torture_comment(tctx, "ALIASINFOALL ignored\n"); break; } - status = dcerpc_samr_SetAliasInfo(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("SetAliasInfo level %u failed - %s\n", - levels[i], nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetAliasInfo_r(b, tctx, &r), + "SetAliasInfo failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "SetAliasInfo level %u failed - %s\n", + levels[i], nt_errstr(r.out.result)); ret = false; } @@ -1307,10 +1393,11 @@ static bool test_SetAliasInfo(struct dcerpc_pipe *p, struct torture_context *tct q.in.level = levels[i]; q.out.info = &info; - status = dcerpc_samr_QueryAliasInfo(p, tctx, &q); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryAliasInfo level %u failed - %s\n", - levels[i], nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryAliasInfo_r(b, tctx, &q), + "QueryAliasInfo failed"); + if (!NT_STATUS_IS_OK(q.out.result)) { + torture_warning(tctx, "QueryAliasInfo level %u failed - %s\n", + levels[i], nt_errstr(q.out.result)); ret = false; } } @@ -1318,20 +1405,21 @@ static bool test_SetAliasInfo(struct dcerpc_pipe *p, struct torture_context *tct return ret; } -static bool test_GetGroupsForUser(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_GetGroupsForUser(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *user_handle) { struct samr_GetGroupsForUser r; struct samr_RidWithAttributeArray *rids = NULL; - NTSTATUS status; - torture_comment(tctx, "testing GetGroupsForUser\n"); + torture_comment(tctx, "Testing GetGroupsForUser\n"); r.in.user_handle = user_handle; r.out.rids = &rids; - status = dcerpc_samr_GetGroupsForUser(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetGroupsForUser"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetGroupsForUser_r(b, tctx, &r), + "GetGroupsForUser failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetGroupsForUser failed"); return true; @@ -1340,43 +1428,47 @@ static bool test_GetGroupsForUser(struct dcerpc_pipe *p, struct torture_context static bool test_GetDomPwInfo(struct dcerpc_pipe *p, struct torture_context *tctx, struct lsa_String *domain_name) { - NTSTATUS status; struct samr_GetDomPwInfo r; struct samr_PwInfo info; + struct dcerpc_binding_handle *b = p->binding_handle; r.in.domain_name = domain_name; r.out.info = &info; torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string); - status = dcerpc_samr_GetDomPwInfo(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetDomPwInfo"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r), + "GetDomPwInfo failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed"); r.in.domain_name->string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string); - status = dcerpc_samr_GetDomPwInfo(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetDomPwInfo"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r), + "GetDomPwInfo failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed"); r.in.domain_name->string = "\\\\__NONAME__"; torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string); - status = dcerpc_samr_GetDomPwInfo(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetDomPwInfo"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r), + "GetDomPwInfo failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed"); r.in.domain_name->string = "\\\\Builtin"; torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string); - status = dcerpc_samr_GetDomPwInfo(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetDomPwInfo"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r), + "GetDomPwInfo failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed"); return true; } -static bool test_GetUserPwInfo(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_GetUserPwInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_GetUserPwInfo r; struct samr_PwInfo info; @@ -1385,13 +1477,15 @@ static bool test_GetUserPwInfo(struct dcerpc_pipe *p, struct torture_context *tc r.in.user_handle = handle; r.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetUserPwInfo"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &r), + "GetUserPwInfo failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetUserPwInfo"); return true; } -static NTSTATUS test_LookupName(struct dcerpc_pipe *p, struct torture_context *tctx, +static NTSTATUS test_LookupName(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *domain_handle, const char *name, uint32_t *rid) { @@ -1407,58 +1501,74 @@ static NTSTATUS test_LookupName(struct dcerpc_pipe *p, struct torture_context *t n.in.names = sname; n.out.rids = &rids; n.out.types = &types; - status = dcerpc_samr_LookupNames(p, tctx, &n); - if (NT_STATUS_IS_OK(status)) { + status = dcerpc_samr_LookupNames_r(b, tctx, &n); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (NT_STATUS_IS_OK(n.out.result)) { *rid = n.out.rids->ids[0]; } else { - return status; + return n.out.result; } init_lsa_String(&sname[1], "xxNONAMExx"); n.in.num_names = 2; - status = dcerpc_samr_LookupNames(p, tctx, &n); - if (!NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) { - printf("LookupNames[2] failed - %s\n", nt_errstr(status)); - if (NT_STATUS_IS_OK(status)) { + status = dcerpc_samr_LookupNames_r(b, tctx, &n); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_EQUAL(n.out.result, STATUS_SOME_UNMAPPED)) { + torture_warning(tctx, "LookupNames[2] failed - %s\n", nt_errstr(n.out.result)); + if (NT_STATUS_IS_OK(n.out.result)) { return NT_STATUS_UNSUCCESSFUL; } - return status; + return n.out.result; } n.in.num_names = 0; - status = dcerpc_samr_LookupNames(p, tctx, &n); + status = dcerpc_samr_LookupNames_r(b, tctx, &n); if (!NT_STATUS_IS_OK(status)) { - printf("LookupNames[0] failed - %s\n", nt_errstr(status)); return status; } + if (!NT_STATUS_IS_OK(n.out.result)) { + torture_warning(tctx, "LookupNames[0] failed - %s\n", nt_errstr(status)); + return n.out.result; + } init_lsa_String(&sname[0], "xxNONAMExx"); n.in.num_names = 1; - status = dcerpc_samr_LookupNames(p, tctx, &n); - if (!NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { - printf("LookupNames[1 bad name] failed - %s\n", nt_errstr(status)); - if (NT_STATUS_IS_OK(status)) { + status = dcerpc_samr_LookupNames_r(b, tctx, &n); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_EQUAL(n.out.result, NT_STATUS_NONE_MAPPED)) { + torture_warning(tctx, "LookupNames[1 bad name] failed - %s\n", nt_errstr(n.out.result)); + if (NT_STATUS_IS_OK(n.out.result)) { return NT_STATUS_UNSUCCESSFUL; } - return status; + return n.out.result; } init_lsa_String(&sname[0], "xxNONAMExx"); init_lsa_String(&sname[1], "xxNONAME2xx"); n.in.num_names = 2; - status = dcerpc_samr_LookupNames(p, tctx, &n); - if (!NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { - printf("LookupNames[2 bad names] failed - %s\n", nt_errstr(status)); - if (NT_STATUS_IS_OK(status)) { + status = dcerpc_samr_LookupNames_r(b, tctx, &n); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_EQUAL(n.out.result, NT_STATUS_NONE_MAPPED)) { + torture_warning(tctx, "LookupNames[2 bad names] failed - %s\n", nt_errstr(n.out.result)); + if (NT_STATUS_IS_OK(n.out.result)) { return NT_STATUS_UNSUCCESSFUL; } - return status; + return n.out.result; } return NT_STATUS_OK; } -static NTSTATUS test_OpenUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static NTSTATUS test_OpenUser_byname(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *domain_handle, const char *name, struct policy_handle *user_handle) { @@ -1466,7 +1576,7 @@ static NTSTATUS test_OpenUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct samr_OpenUser r; uint32_t rid; - status = test_LookupName(p, mem_ctx, domain_handle, name, &rid); + status = test_LookupName(b, tctx, domain_handle, name, &rid); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1475,16 +1585,20 @@ static NTSTATUS test_OpenUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.in.rid = rid; r.out.user_handle = user_handle; - status = dcerpc_samr_OpenUser(p, mem_ctx, &r); + status = dcerpc_samr_OpenUser_r(b, tctx, &r); if (!NT_STATUS_IS_OK(status)) { - printf("OpenUser_byname(%s -> %d) failed - %s\n", name, rid, nt_errstr(status)); + return status; + } + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "OpenUser_byname(%s -> %d) failed - %s\n", name, rid, nt_errstr(r.out.result)); } - return status; + return r.out.result; } #if 0 -static bool test_ChangePasswordNT3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_ChangePasswordNT3(struct dcerpc_pipe *p, + struct torture_context *tctx, struct policy_handle *handle) { NTSTATUS status; @@ -1497,15 +1611,15 @@ static bool test_ChangePasswordNT3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; - status = test_OpenUser_byname(p, mem_ctx, handle, "testuser", &user_handle); + status = test_OpenUser_byname(p, tctx, handle, "testuser", &user_handle); if (!NT_STATUS_IS_OK(status)) { return false; } - printf("Testing ChangePasswordUser for user 'testuser'\n"); + torture_comment(tctx, "Testing ChangePasswordUser for user 'testuser'\n"); - printf("old password: %s\n", oldpass); - printf("new password: %s\n", newpass); + torture_comment(tctx, "old password: %s\n", oldpass); + torture_comment(tctx, "new password: %s\n", newpass); E_md4hash(oldpass, old_nt_hash); E_md4hash(newpass, new_nt_hash); @@ -1531,13 +1645,14 @@ static bool test_ChangePasswordNT3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("ChangePasswordUser failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "ChangePasswordUser failed - %s\n", nt_errstr(r.out.result)); ret = false; } - if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) { + if (!test_samr_handle_Close(p, tctx, &user_handle)) { ret = false; } @@ -1545,8 +1660,9 @@ static bool test_ChangePasswordNT3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } #endif -static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_context *tctx, - const char *acct_name, +static bool test_ChangePasswordUser(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + const char *acct_name, struct policy_handle *handle, char **password) { NTSTATUS status; @@ -1564,22 +1680,23 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex struct samr_PwInfo info; int policy_min_pw_len = 0; - status = test_OpenUser_byname(p, tctx, handle, acct_name, &user_handle); + status = test_OpenUser_byname(b, tctx, handle, acct_name, &user_handle); if (!NT_STATUS_IS_OK(status)) { return false; } pwp.in.user_handle = &user_handle; pwp.out.info = &info; - status = dcerpc_samr_GetUserPwInfo(p, tctx, &pwp); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp), + "GetUserPwInfo failed"); + if (NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); torture_comment(tctx, "Testing ChangePasswordUser\n"); - torture_assert(tctx, *password != NULL, + torture_assert(tctx, *password != NULL, "Failing ChangePasswordUser as old password was NULL. Previous test failed?"); oldpass = *password; @@ -1610,8 +1727,9 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, status, NT_STATUS_WRONG_PASSWORD, + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM hash"); /* Unbreak the LM hash */ @@ -1631,8 +1749,9 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, status, NT_STATUS_WRONG_PASSWORD, + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "expected NT_STATUS_WRONG_PASSWORD because we broke the NT hash"); /* Unbreak the NT hash */ @@ -1652,9 +1771,10 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex hash6.hash[0]++; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM cross-hash, got %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM cross-hash, got %s\n", nt_errstr(r.out.result)); ret = false; } @@ -1675,9 +1795,10 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT cross-hash, got %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT cross-hash, got %s\n", nt_errstr(r.out.result)); ret = false; } @@ -1705,12 +1826,13 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 0; r.in.lm_cross = NULL; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (NT_STATUS_IS_OK(r.out.result)) { changed = true; *password = newpass; - } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, status)) { - printf("ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(status)); + } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, r.out.result)) { + torture_warning(tctx, "ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(r.out.result)); ret = false; } @@ -1743,12 +1865,13 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (NT_STATUS_IS_OK(r.out.result)) { changed = true; *password = newpass; - } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, status)) { - printf("ChangePasswordUser failed: expected NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED, got %s\n", nt_errstr(status)); + } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, r.out.result)) { + torture_warning(tctx, "ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(r.out.result)); ret = false; } @@ -1781,11 +1904,12 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.cross2_present = 1; r.in.lm_cross = &hash6; - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - printf("ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); - } else if (!NT_STATUS_IS_OK(status)) { - printf("ChangePasswordUser failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + torture_comment(tctx, "ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result)); + } else if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "ChangePasswordUser failed - %s\n", nt_errstr(r.out.result)); ret = false; } else { changed = true; @@ -1805,17 +1929,18 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex r.in.lm_cross = &hash6; if (changed) { - status = dcerpc_samr_ChangePasswordUser(p, tctx, &r); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - printf("ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); - } else if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we already changed the password, got %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r), + "ChangePasswordUser failed"); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + torture_comment(tctx, "ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result)); + } else if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we already changed the password, got %s\n", nt_errstr(r.out.result)); ret = false; } } - - if (!test_samr_handle_Close(p, tctx, &user_handle)) { + + if (!test_samr_handle_Close(b, tctx, &user_handle)) { ret = false; } @@ -1823,11 +1948,11 @@ static bool test_ChangePasswordUser(struct dcerpc_pipe *p, struct torture_contex } -static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, + struct torture_context *tctx, const char *acct_name, struct policy_handle *handle, char **password) { - NTSTATUS status; struct samr_OemChangePasswordUser2 r; bool ret = true; struct samr_Password lm_verifier; @@ -1835,6 +1960,7 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co struct lsa_AsciiString server, account, account_bad; char *oldpass; char *newpass; + struct dcerpc_binding_handle *b = p->binding_handle; uint8_t old_lm_hash[16], new_lm_hash[16]; struct samr_GetDomPwInfo dom_pw_info; @@ -1849,13 +1975,14 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co torture_comment(tctx, "Testing OemChangePasswordUser2\n"); - torture_assert(tctx, *password != NULL, + torture_assert(tctx, *password != NULL, "Failing OemChangePasswordUser2 as old password was NULL. Previous test failed?"); oldpass = *password; - status = dcerpc_samr_GetDomPwInfo(p, tctx, &dom_pw_info); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &dom_pw_info), + "GetDomPwInfo failed"); + if (NT_STATUS_IS_OK(dom_pw_info.out.result)) { policy_min_pw_len = dom_pw_info.out.info->min_password_length; } @@ -1879,12 +2006,13 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co /* Break the verification */ lm_verifier.hash[0]++; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) - && !NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) + && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1901,12 +2029,13 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co r.in.password = &lm_pass; r.in.hash = &lm_verifier; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) - && !NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) + && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1918,12 +2047,13 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co r.in.password = &lm_pass; r.in.hash = NULL; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) - && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER (or at least 'PASSWORD_RESTRICTON') for no supplied validation hash - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) + && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER (or at least 'PASSWORD_RESTRICTON') for no supplied validation hash - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1931,11 +2061,12 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co account_bad.string = TEST_ACCOUNT_NAME "XX"; r.in.account = &account_bad; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied validation hash and invalid user - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied validation hash and invalid user - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1945,11 +2076,12 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co r.in.password = &lm_pass; r.in.hash = &lm_verifier; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD for invalid user - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD for invalid user - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1959,11 +2091,12 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co r.in.password = NULL; r.in.hash = &lm_verifier; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); - if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied password and invalid user - %s\n", - nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_warning(tctx, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied password and invalid user - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -1979,11 +2112,13 @@ static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p, struct torture_co r.in.password = &lm_pass; r.in.hash = &lm_verifier; - status = dcerpc_samr_OemChangePasswordUser2(p, tctx, &r); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - printf("OemChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); - } else if (!NT_STATUS_IS_OK(status)) { - printf("OemChangePasswordUser2 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r), + "OemChangePasswordUser2 failed"); + + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + torture_comment(tctx, "OemChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result)); + } else if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "OemChangePasswordUser2 failed - %s\n", nt_errstr(r.out.result)); ret = false; } else { *password = newpass; @@ -1998,13 +2133,13 @@ static bool test_ChangePasswordUser2(struct dcerpc_pipe *p, struct torture_conte char **password, char *newpass, bool allow_password_restriction) { - NTSTATUS status; struct samr_ChangePasswordUser2 r; bool ret = true; struct lsa_String server, account; struct samr_CryptPassword nt_pass, lm_pass; struct samr_Password nt_verifier, lm_verifier; char *oldpass; + struct dcerpc_binding_handle *b = p->binding_handle; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; @@ -2019,19 +2154,20 @@ static bool test_ChangePasswordUser2(struct dcerpc_pipe *p, struct torture_conte torture_comment(tctx, "Testing ChangePasswordUser2 on %s\n", acct_name); - torture_assert(tctx, *password != NULL, + torture_assert(tctx, *password != NULL, "Failing ChangePasswordUser2 as old password was NULL. Previous test failed?"); oldpass = *password; if (!newpass) { int policy_min_pw_len = 0; - status = dcerpc_samr_GetDomPwInfo(p, tctx, &dom_pw_info); - if (NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &dom_pw_info), + "GetDomPwInfo failed"); + if (NT_STATUS_IS_OK(dom_pw_info.out.result)) { policy_min_pw_len = dom_pw_info.out.info->min_password_length; } newpass = samr_rand_pass(tctx, policy_min_pw_len); - } + } server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); init_lsa_String(&account, acct_name); @@ -2058,11 +2194,13 @@ static bool test_ChangePasswordUser2(struct dcerpc_pipe *p, struct torture_conte r.in.lm_password = &lm_pass; r.in.lm_verifier = &lm_verifier; - status = dcerpc_samr_ChangePasswordUser2(p, tctx, &r); - if (allow_password_restriction && NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - printf("ChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); - } else if (!NT_STATUS_IS_OK(status)) { - printf("ChangePasswordUser2 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser2_r(b, tctx, &r), + "ChangePasswordUser2 failed"); + + if (allow_password_restriction && NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + torture_comment(tctx, "ChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result)); + } else if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "ChangePasswordUser2 failed - %s\n", nt_errstr(r.out.result)); ret = false; } else { *password = newpass; @@ -2072,7 +2210,7 @@ static bool test_ChangePasswordUser2(struct dcerpc_pipe *p, struct torture_conte } -bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tctx, +bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tctx, const char *account_string, int policy_min_pw_len, char **password, @@ -2080,18 +2218,18 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct NTTIME last_password_change, bool handle_reject_reason) { - NTSTATUS status; struct samr_ChangePasswordUser3 r; bool ret = true; struct lsa_String server, account, account_bad; struct samr_CryptPassword nt_pass, lm_pass; struct samr_Password nt_verifier, lm_verifier; char *oldpass; + struct dcerpc_binding_handle *b = p->binding_handle; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; NTTIME t; struct samr_DomInfo1 *dominfo = NULL; - struct samr_ChangeReject *reject = NULL; + struct userPwdChangeFailureInformation *reject = NULL; torture_comment(tctx, "Testing ChangePasswordUser3\n"); @@ -2107,7 +2245,7 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct torture_comment(tctx, "Using password '%s'\n", newpass); } - torture_assert(tctx, *password != NULL, + torture_assert(tctx, *password != NULL, "Failing ChangePasswordUser3 as old password was NULL. Previous test failed?"); oldpass = *password; @@ -2127,7 +2265,7 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct encode_pw_buffer(nt_pass.data, newpass, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); - + /* Break the verification */ nt_verifier.hash[0]++; @@ -2142,14 +2280,15 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct r.out.dominfo = &dominfo; r.out.reject = &reject; - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) && - (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD))) { - printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n", - nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) && + (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD))) { + torture_warning(tctx, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n", + nt_errstr(r.out.result)); ret = false; } - + encode_pw_buffer(lm_pass.data, newpass, STR_UNICODE); arcfour_crypt(lm_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash); @@ -2161,7 +2300,7 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct /* Unbreak it again */ old_nt_hash[0]--; E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); - + r.in.server = &server; r.in.account = &account; r.in.nt_password = &nt_pass; @@ -2173,22 +2312,24 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct r.out.dominfo = &dominfo; r.out.reject = &reject; - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) && - (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD))) { - printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", - nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) && + (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD))) { + torture_warning(tctx, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", + nt_errstr(r.out.result)); ret = false; } - + /* This shouldn't be a valid name */ init_lsa_String(&account_bad, talloc_asprintf(tctx, "%sXX", account_string)); r.in.account = &account_bad; - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD for invalid username - %s\n", - nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) { + torture_warning(tctx, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD for invalid username - %s\n", + nt_errstr(r.out.result)); ret = false; } @@ -2219,25 +2360,26 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct unix_to_nt_time(&t, time(NULL)); - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) && dominfo && reject && handle_reject_reason && (!null_nttime(last_password_change) || !dominfo->min_password_age)) { if (dominfo->password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE ) { - if (reject && (reject->reason != SAMR_REJECT_OTHER)) { - printf("expected SAMR_REJECT_OTHER (%d), got %d\n", - SAMR_REJECT_OTHER, reject->reason); + if (reject && (reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR)) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n", + SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason); return false; } } /* We tested the order of precendence which is as follows: - - * pwd min_age + + * pwd min_age * pwd length * pwd complexity * pwd history @@ -2247,57 +2389,58 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct if ((dominfo->min_password_age > 0) && !null_nttime(last_password_change) && (last_password_change + dominfo->min_password_age > t)) { - if (reject->reason != SAMR_REJECT_OTHER) { - printf("expected SAMR_REJECT_OTHER (%d), got %d\n", - SAMR_REJECT_OTHER, reject->reason); + if (reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n", + SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason); return false; } } else if ((dominfo->min_password_length > 0) && (strlen(newpass) < dominfo->min_password_length)) { - if (reject->reason != SAMR_REJECT_TOO_SHORT) { - printf("expected SAMR_REJECT_TOO_SHORT (%d), got %d\n", - SAMR_REJECT_TOO_SHORT, reject->reason); + if (reject->extendedFailureReason != SAM_PWD_CHANGE_PASSWORD_TOO_SHORT) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_PASSWORD_TOO_SHORT (%d), got %d\n", + SAM_PWD_CHANGE_PASSWORD_TOO_SHORT, reject->extendedFailureReason); return false; } } else if ((dominfo->password_history_length > 0) && strequal(oldpass, newpass)) { - if (reject->reason != SAMR_REJECT_IN_HISTORY) { - printf("expected SAMR_REJECT_IN_HISTORY (%d), got %d\n", - SAMR_REJECT_IN_HISTORY, reject->reason); + if (reject->extendedFailureReason != SAM_PWD_CHANGE_PWD_IN_HISTORY) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_PWD_IN_HISTORY (%d), got %d\n", + SAM_PWD_CHANGE_PWD_IN_HISTORY, reject->extendedFailureReason); return false; } } else if (dominfo->password_properties & DOMAIN_PASSWORD_COMPLEX) { - if (reject->reason != SAMR_REJECT_COMPLEXITY) { - printf("expected SAMR_REJECT_COMPLEXITY (%d), got %d\n", - SAMR_REJECT_COMPLEXITY, reject->reason); + if (reject->extendedFailureReason != SAM_PWD_CHANGE_NOT_COMPLEX) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NOT_COMPLEX (%d), got %d\n", + SAM_PWD_CHANGE_NOT_COMPLEX, reject->extendedFailureReason); return false; } } - if (reject->reason == SAMR_REJECT_TOO_SHORT) { + if (reject->extendedFailureReason == SAM_PWD_CHANGE_PASSWORD_TOO_SHORT) { /* retry with adjusted size */ - return test_ChangePasswordUser3(p, tctx, account_string, + return test_ChangePasswordUser3(p, tctx, account_string, dominfo->min_password_length, - password, NULL, 0, false); + password, NULL, 0, false); } - } else if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - if (reject && reject->reason != SAMR_REJECT_OTHER) { - printf("expected SAMR_REJECT_OTHER (%d), got %d\n", - SAMR_REJECT_OTHER, reject->reason); + } else if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n", + SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason); return false; } /* Perhaps the server has a 'min password age' set? */ - } else { - torture_assert_ntstatus_ok(tctx, status, "ChangePasswordUser3"); + } else { + torture_assert_ntstatus_ok(tctx, r.out.result, "ChangePasswordUser3"); + *password = talloc_strdup(tctx, newpass); } @@ -2306,7 +2449,7 @@ bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tct bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_context *tctx, const char *account_string, - struct policy_handle *handle, + struct policy_handle *handle, char **password) { NTSTATUS status; @@ -2325,14 +2468,15 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex DATA_BLOB new_random_pass; char *newpass; char *oldpass; + struct dcerpc_binding_handle *b = p->binding_handle; uint8_t old_nt_hash[16], new_nt_hash[16]; NTTIME t; struct samr_DomInfo1 *dominfo = NULL; - struct samr_ChangeReject *reject = NULL; + struct userPwdChangeFailureInformation *reject = NULL; new_random_pass = samr_very_rand_pass(tctx, 128); - torture_assert(tctx, *password != NULL, + torture_assert(tctx, *password != NULL, "Failing ChangePasswordUser3 as old password was NULL. Previous test failed?"); oldpass = *password; @@ -2351,7 +2495,7 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex status = dcerpc_fetch_session_key(p, &session_key); if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u - no session key - %s\n", + torture_warning(tctx, "SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); return false; } @@ -2368,10 +2512,11 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex) with a password made up of only random bytes\n"); - status = dcerpc_samr_SetUserInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetUserInfo level %u failed - %s\n", - s.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s), + "SetUserInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetUserInfo level %u failed - %s\n", + s.in.level, nt_errstr(s.out.result)); ret = false; } @@ -2400,21 +2545,22 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex unix_to_nt_time(&t, time(NULL)); - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - if (reject && reject->reason != SAMR_REJECT_OTHER) { - printf("expected SAMR_REJECT_OTHER (%d), got %d\n", - SAMR_REJECT_OTHER, reject->reason); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n", + SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason); return false; } /* Perhaps the server has a 'min password age' set? */ - } else if (!NT_STATUS_IS_OK(status)) { - printf("ChangePasswordUser3 failed - %s\n", nt_errstr(status)); + } else if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "ChangePasswordUser3 failed - %s\n", nt_errstr(r.out.result)); ret = false; } - + newpass = samr_rand_pass(tctx, 128); mdfour(old_nt_hash, new_random_pass.data, new_random_pass.length); @@ -2438,18 +2584,19 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex unix_to_nt_time(&t, time(NULL)); - status = dcerpc_samr_ChangePasswordUser3(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r), + "ChangePasswordUser3 failed"); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { - if (reject && reject->reason != SAMR_REJECT_OTHER) { - printf("expected SAMR_REJECT_OTHER (%d), got %d\n", - SAMR_REJECT_OTHER, reject->reason); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { + if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) { + torture_warning(tctx, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n", + SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason); return false; } /* Perhaps the server has a 'min password age' set? */ } else { - torture_assert_ntstatus_ok(tctx, status, "ChangePasswordUser3 (on second random password)"); + torture_assert_ntstatus_ok(tctx, r.out.result, "ChangePasswordUser3 (on second random password)"); *password = talloc_strdup(tctx, newpass); } @@ -2457,60 +2604,63 @@ bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_contex } -static bool test_GetMembersInAlias(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *alias_handle) +static bool test_GetMembersInAlias(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *alias_handle) { struct samr_GetMembersInAlias r; struct lsa_SidArray sids; - NTSTATUS status; torture_comment(tctx, "Testing GetMembersInAlias\n"); r.in.alias_handle = alias_handle; r.out.sids = &sids; - status = dcerpc_samr_GetMembersInAlias(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "GetMembersInAlias"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetMembersInAlias_r(b, tctx, &r), + "GetMembersInAlias failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "GetMembersInAlias failed"); return true; } -static bool test_AddMemberToAlias(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_AddMemberToAlias(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *alias_handle, const struct dom_sid *domain_sid) { struct samr_AddAliasMember r; struct samr_DeleteAliasMember d; - NTSTATUS status; struct dom_sid *sid; sid = dom_sid_add_rid(tctx, domain_sid, 512); - torture_comment(tctx, "testing AddAliasMember\n"); + torture_comment(tctx, "Testing AddAliasMember\n"); r.in.alias_handle = alias_handle; r.in.sid = sid; - status = dcerpc_samr_AddAliasMember(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "AddAliasMember"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddAliasMember_r(b, tctx, &r), + "AddAliasMember failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "AddAliasMember failed"); d.in.alias_handle = alias_handle; d.in.sid = sid; - status = dcerpc_samr_DeleteAliasMember(p, tctx, &d); - torture_assert_ntstatus_ok(tctx, status, "DelAliasMember"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteAliasMember_r(b, tctx, &d), + "DeleteAliasMember failed"); + torture_assert_ntstatus_ok(tctx, d.out.result, "DelAliasMember failed"); return true; } -static bool test_AddMultipleMembersToAlias(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_AddMultipleMembersToAlias(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *alias_handle) { struct samr_AddMultipleMembersToAlias a; struct samr_RemoveMultipleMembersFromAlias r; - NTSTATUS status; struct lsa_SidArray sids; - torture_comment(tctx, "testing AddMultipleMembersToAlias\n"); + torture_comment(tctx, "Testing AddMultipleMembersToAlias\n"); a.in.alias_handle = alias_handle; a.in.sids = &sids; @@ -2521,47 +2671,101 @@ static bool test_AddMultipleMembersToAlias(struct dcerpc_pipe *p, struct torture sids.sids[1].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-2"); sids.sids[2].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-3"); - status = dcerpc_samr_AddMultipleMembersToAlias(p, tctx, &a); - torture_assert_ntstatus_ok(tctx, status, "AddMultipleMembersToAlias"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddMultipleMembersToAlias_r(b, tctx, &a), + "AddMultipleMembersToAlias failed"); + torture_assert_ntstatus_ok(tctx, a.out.result, "AddMultipleMembersToAlias"); - torture_comment(tctx, "testing RemoveMultipleMembersFromAlias\n"); + torture_comment(tctx, "Testing RemoveMultipleMembersFromAlias\n"); r.in.alias_handle = alias_handle; r.in.sids = &sids; - status = dcerpc_samr_RemoveMultipleMembersFromAlias(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "RemoveMultipleMembersFromAlias"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r), + "RemoveMultipleMembersFromAlias failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMultipleMembersFromAlias failed"); /* strange! removing twice doesn't give any error */ - status = dcerpc_samr_RemoveMultipleMembersFromAlias(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "RemoveMultipleMembersFromAlias"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r), + "RemoveMultipleMembersFromAlias failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMultipleMembersFromAlias failed"); /* but removing an alias that isn't there does */ sids.sids[2].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-4"); - status = dcerpc_samr_RemoveMultipleMembersFromAlias(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, "RemoveMultipleMembersFromAlias"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r), + "RemoveMultipleMembersFromAlias failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND, "RemoveMultipleMembersFromAlias"); + + return true; +} + +static bool test_GetAliasMembership(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle) +{ + struct samr_GetAliasMembership r; + struct lsa_SidArray sids; + struct samr_Ids rids; + + torture_comment(tctx, "Testing GetAliasMembership\n"); + + r.in.domain_handle = domain_handle; + r.in.sids = &sids; + r.out.rids = &rids; + + sids.num_sids = 0; + sids.sids = talloc_zero_array(tctx, struct lsa_SidPtr, sids.num_sids); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r), + "GetAliasMembership failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_GetAliasMembership failed"); + + torture_assert_int_equal(tctx, sids.num_sids, rids.count, + "protocol misbehaviour"); + + sids.num_sids = 1; + sids.sids = talloc_zero_array(tctx, struct lsa_SidPtr, sids.num_sids); + sids.sids[0].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-1"); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r), + "samr_GetAliasMembership failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_GetAliasMembership failed"); + +#if 0 + /* only true for w2k8 it seems + * win7, xp, w2k3 will return a 0 length array pointer */ + + if (rids.ids && (rids.count == 0)) { + torture_fail(tctx, "samr_GetAliasMembership returned 0 count and a rids array"); + } +#endif + if (!rids.ids && rids.count) { + torture_fail(tctx, "samr_GetAliasMembership returned non-0 count but no rids"); + } return true; } -static bool test_TestPrivateFunctionsUser(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *user_handle) +static bool test_TestPrivateFunctionsUser(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *user_handle) { struct samr_TestPrivateFunctionsUser r; - NTSTATUS status; torture_comment(tctx, "Testing TestPrivateFunctionsUser\n"); r.in.user_handle = user_handle; - status = dcerpc_samr_TestPrivateFunctionsUser(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_IMPLEMENTED, "TestPrivateFunctionsUser"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_TestPrivateFunctionsUser_r(b, tctx, &r), + "TestPrivateFunctionsUser failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_IMPLEMENTED, "TestPrivateFunctionsUser"); return true; } -static bool test_QueryUserInfo_pwdlastset(struct dcerpc_pipe *p, +static bool test_QueryUserInfo_pwdlastset(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, bool use_info2, @@ -2587,18 +2791,22 @@ static bool test_QueryUserInfo_pwdlastset(struct dcerpc_pipe *p, r2.in.user_handle = handle; r2.in.level = levels[i]; r2.out.info = &info; - status = dcerpc_samr_QueryUserInfo2(p, tctx, &r2); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo2_r(b, tctx, &r2), + "QueryUserInfo2 failed"); + status = r2.out.result; } else { r.in.user_handle = handle; r.in.level = levels[i]; r.out.info = &info; - status = dcerpc_samr_QueryUserInfo(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r), + "QueryUserInfo failed"); + status = r.out.result; } if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) { - printf("QueryUserInfo%s level %u failed - %s\n", + torture_warning(tctx, "QueryUserInfo%s level %u failed - %s\n", use_info2 ? "2":"", levels[i], nt_errstr(status)); return false; } @@ -2624,122 +2832,139 @@ static bool test_QueryUserInfo_pwdlastset(struct dcerpc_pipe *p, *pwdlastset = pwdlastset21; - torture_comment(tctx, "(pwdlastset: %lld)\n", *pwdlastset); + torture_comment(tctx, "(pwdlastset: %llu)\n", + (unsigned long long) *pwdlastset); return true; } -static bool test_SamLogon_Creds(struct dcerpc_pipe *p, struct torture_context *tctx, - struct cli_credentials *machine_credentials, - struct cli_credentials *test_credentials, - struct creds_CredentialState *creds, - NTSTATUS expected_result) +static bool test_SamLogon(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *test_credentials, + NTSTATUS expected_result, + bool interactive) { NTSTATUS status; - struct netr_LogonSamLogon r; - struct netr_Authenticator auth, auth2; + struct netr_LogonSamLogonEx r; union netr_LogonLevel logon; union netr_Validation validation; uint8_t authoritative; + struct netr_IdentityInfo identity; struct netr_NetworkInfo ninfo; + struct netr_PasswordInfo pinfo; DATA_BLOB names_blob, chal, lm_resp, nt_resp; int flags = CLI_CRED_NTLM_AUTH; + uint32_t samlogon_flags = 0; + struct netlogon_creds_CredentialState *creds; + struct netr_Authenticator a; + struct dcerpc_binding_handle *b = p->binding_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_schannel_creds(p->conn->security_state.generic_state, tctx, &creds), ""); - if (lp_client_lanman_auth(tctx->lp_ctx)) { + if (lpcfg_client_lanman_auth(tctx->lp_ctx)) { flags |= CLI_CRED_LANMAN_AUTH; } - if (lp_client_ntlmv2_auth(tctx->lp_ctx)) { + if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) { flags |= CLI_CRED_NTLMv2_AUTH; } cli_credentials_get_ntlm_username_domain(test_credentials, tctx, - &ninfo.identity_info.account_name.string, - &ninfo.identity_info.domain_name.string); + &identity.account_name.string, + &identity.domain_name.string); + + identity.parameter_control = + MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | + MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; + identity.logon_id_low = 0; + identity.logon_id_high = 0; + identity.workstation.string = cli_credentials_get_workstation(test_credentials); + + if (interactive) { + netlogon_creds_client_authenticator(creds, &a); - generate_random_buffer(ninfo.challenge, - sizeof(ninfo.challenge)); - chal = data_blob_const(ninfo.challenge, - sizeof(ninfo.challenge)); + if (!E_deshash(cli_credentials_get_password(test_credentials), pinfo.lmpassword.hash)) { + ZERO_STRUCT(pinfo.lmpassword.hash); + } + E_md4hash(cli_credentials_get_password(test_credentials), pinfo.ntpassword.hash); + + if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + netlogon_creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16); + netlogon_creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16); + } else { + netlogon_creds_des_encrypt(creds, &pinfo.lmpassword); + netlogon_creds_des_encrypt(creds, &pinfo.ntpassword); + } - names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(machine_credentials), - cli_credentials_get_domain(machine_credentials)); + pinfo.identity_info = identity; + logon.password = &pinfo; - status = cli_credentials_get_ntlm_response(test_credentials, tctx, - &flags, - chal, - names_blob, - &lm_resp, &nt_resp, - NULL, NULL); - torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed"); + r.in.logon_level = NetlogonInteractiveInformation; + } else { + generate_random_buffer(ninfo.challenge, + sizeof(ninfo.challenge)); + chal = data_blob_const(ninfo.challenge, + sizeof(ninfo.challenge)); - ninfo.lm.data = lm_resp.data; - ninfo.lm.length = lm_resp.length; + names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(test_credentials), + cli_credentials_get_domain(test_credentials)); - ninfo.nt.data = nt_resp.data; - ninfo.nt.length = nt_resp.length; + status = cli_credentials_get_ntlm_response(test_credentials, tctx, + &flags, + chal, + names_blob, + &lm_resp, &nt_resp, + NULL, NULL); + torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed"); - ninfo.identity_info.parameter_control = - MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | - MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; - ninfo.identity_info.logon_id_low = 0; - ninfo.identity_info.logon_id_high = 0; - ninfo.identity_info.workstation.string = cli_credentials_get_workstation(machine_credentials); + ninfo.lm.data = lm_resp.data; + ninfo.lm.length = lm_resp.length; + + ninfo.nt.data = nt_resp.data; + ninfo.nt.length = nt_resp.length; - logon.network = &ninfo; + ninfo.identity_info = identity; + logon.network = &ninfo; + + r.in.logon_level = NetlogonNetworkInformation; + } r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(machine_credentials); - r.in.credential = &auth; - r.in.return_authenticator = &auth2; - r.in.logon_level = 2; + r.in.computer_name = cli_credentials_get_workstation(test_credentials); r.in.logon = &logon; + r.in.flags = &samlogon_flags; + r.out.flags = &samlogon_flags; r.out.validation = &validation; r.out.authoritative = &authoritative; - d_printf("Testing LogonSamLogon with name %s\n", ninfo.identity_info.account_name.string); + torture_comment(tctx, "Testing LogonSamLogon with name %s\n", identity.account_name.string); - ZERO_STRUCT(auth2); - creds_client_authenticator(creds, &auth); + r.in.validation_level = 6; - r.in.validation_level = 2; - - status = dcerpc_netr_LogonSamLogon(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - torture_assert_ntstatus_equal(tctx, status, expected_result, "LogonSamLogon failed"); + torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), + "netr_LogonSamLogonEx failed"); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) { + r.in.validation_level = 3; + torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), + "netr_LogonSamLogonEx failed"); + } + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_assert_ntstatus_equal(tctx, r.out.result, expected_result, "LogonSamLogonEx failed"); return true; } else { - torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogonEx failed"); } - torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), - "Credential chaining failed"); - return true; } -static bool test_SamLogon(struct torture_context *tctx, - struct dcerpc_pipe *p, - struct cli_credentials *machine_credentials, - struct cli_credentials *test_credentials, - NTSTATUS expected_result) -{ - struct creds_CredentialState *creds; - - if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) { - return false; - } - - return test_SamLogon_Creds(p, tctx, machine_credentials, test_credentials, - creds, expected_result); -} - static bool test_SamLogon_with_creds(struct torture_context *tctx, struct dcerpc_pipe *p, struct cli_credentials *machine_creds, const char *acct_name, - char *password, - NTSTATUS expected_samlogon_result) + const char *password, + NTSTATUS expected_samlogon_result, + bool interactive) { bool ret = true; struct cli_credentials *test_credentials; @@ -2747,20 +2972,19 @@ static bool test_SamLogon_with_creds(struct torture_context *tctx, test_credentials = cli_credentials_init(tctx); cli_credentials_set_workstation(test_credentials, - TEST_ACCOUNT_NAME_PWD, CRED_SPECIFIED); + cli_credentials_get_workstation(machine_creds), CRED_SPECIFIED); cli_credentials_set_domain(test_credentials, - lp_workgroup(tctx->lp_ctx), CRED_SPECIFIED); + cli_credentials_get_domain(machine_creds), CRED_SPECIFIED); cli_credentials_set_username(test_credentials, acct_name, CRED_SPECIFIED); cli_credentials_set_password(test_credentials, password, CRED_SPECIFIED); - cli_credentials_set_secure_channel_type(test_credentials, SEC_CHAN_BDC); - printf("testing samlogon as %s@%s password: %s\n", - acct_name, TEST_ACCOUNT_NAME_PWD, password); + torture_comment(tctx, "Testing samlogon (%s) as %s password: %s\n", + interactive ? "interactive" : "network", acct_name, password); - if (!test_SamLogon(tctx, p, machine_creds, test_credentials, - expected_samlogon_result)) { + if (!test_SamLogon(tctx, p, test_credentials, + expected_samlogon_result, interactive)) { torture_warning(tctx, "new password did not work\n"); ret = false; } @@ -2786,6 +3010,7 @@ static bool test_SetPassword_level(struct dcerpc_pipe *p, { const char *fields = NULL; bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; switch (level) { case 21: @@ -2812,7 +3037,7 @@ static bool test_SetPassword_level(struct dcerpc_pipe *p, ret = false; } - if (!test_QueryUserInfo_pwdlastset(p, tctx, handle, + if (!test_QueryUserInfo_pwdlastset(b, tctx, handle, use_queryinfo2, pwdlastset)) { ret = false; @@ -2826,13 +3051,37 @@ static bool test_SetPassword_level(struct dcerpc_pipe *p, machine_creds, acct_name, *password, - expected_samlogon_result)) { + expected_samlogon_result, + false)) { ret = false; } return ret; } +static bool setup_schannel_netlogon_pipe(struct torture_context *tctx, + struct cli_credentials *credentials, + struct dcerpc_pipe **p) +{ + struct dcerpc_binding *b; + + torture_assert_ntstatus_ok(tctx, torture_rpc_binding(tctx, &b), + "failed to get rpc binding"); + + /* We have to use schannel, otherwise the SamLogonEx fails + * with INTERNAL_ERROR */ + + b->flags &= ~DCERPC_AUTH_OPTIONS; + b->flags |= DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128; + + torture_assert_ntstatus_ok(tctx, + dcerpc_pipe_connect_b(tctx, p, b, &ndr_table_netlogon, + credentials, tctx->ev, tctx->lp_ctx), + "failed to bind to netlogon"); + + return true; +} + static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t acct_flags, @@ -2843,10 +3092,10 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, { int s = 0, q = 0, f = 0, l = 0, z = 0; bool ret = true; - int delay = 500000; + int delay = 50000; bool set_levels[] = { false, true }; bool query_levels[] = { false, true }; - uint32_t levels[] = { 18, 21, 23, 24, 25, 26 }; + uint32_t levels[] = { 18, 21, 26, 23, 24, 25 }; /* Second half only used when TEST_ALL_LEVELS defined */ uint32_t nonzeros[] = { 1, 24 }; uint32_t fields_present[] = { 0, @@ -2862,28 +3111,30 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT | SAMR_FIELD_EXPIRED_FLAG, SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT | SAMR_FIELD_LAST_PWD_CHANGE | SAMR_FIELD_EXPIRED_FLAG }; - NTSTATUS status; struct dcerpc_pipe *np = NULL; - if (torture_setting_bool(tctx, "samba3", false)) { - delay = 1000000; - printf("Samba3 has second granularity, setting delay to: %d\n", + if (torture_setting_bool(tctx, "samba3", false) || + torture_setting_bool(tctx, "samba4", false)) { + delay = 999999; + torture_comment(tctx, "Samba3 has second granularity, setting delay to: %d\n", delay); } - status = torture_rpc_connection(tctx, &np, &ndr_table_netlogon); - if (!NT_STATUS_IS_OK(status)) { - return false; - } + torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), ""); /* set to 1 to enable testing for all possible opcode (SetUserInfo, SetUserInfo2, QueryUserInfo, QueryUserInfo2) combinations */ #if 0 +#define TEST_ALL_LEVELS 1 #define TEST_SET_LEVELS 1 #define TEST_QUERY_LEVELS 1 #endif +#ifdef TEST_ALL_LEVELS for (l=0; l 0) && (pwdlastset_new > 0) && - (pwdlastset_old >= pwdlastset_new)) { - torture_warning(tctx, "pwdlastset not increasing\n"); - ret = false; - } - break; } + pwdlastset_old = pwdlastset_new; + usleep(delay); /* set #2 */ @@ -3014,7 +3261,6 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, case 21: case 23: case 25: - /* SAMR_FIELD_EXPIRED_FLAG has not been set and no * password has been changed, old and new pwdlastset * need to be the same value */ @@ -3027,19 +3273,22 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, pwdlastset_new, "pwdlastset must be equal"); break; } + break; default: if (pwdlastset_old >= pwdlastset_new) { torture_warning(tctx, "pwdLastSet test failed: " - "expected last pwdlastset (%lld) < new pwdlastset (%lld)\n", - pwdlastset_old, pwdlastset_new); + "expected last pwdlastset (%llu) < new pwdlastset (%llu)\n", + (unsigned long long) pwdlastset_old, + (unsigned long long) pwdlastset_new); ret = false; } if (pwdlastset_new == 0) { torture_warning(tctx, "pwdLastSet test failed: " - "expected non-0 pwdlastset, got: %lld\n", - pwdlastset_new); + "expected non-0 pwdlastset, got: %llu\n", + (unsigned long long) pwdlastset_new); ret = false; } + break; } switch (levels[l]) { @@ -3054,13 +3303,6 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, ret = false; } break; - default: - if ((pwdlastset_old > 0) && (pwdlastset_new > 0) && - (pwdlastset_old >= pwdlastset_new)) { - torture_warning(tctx, "pwdlastset not increasing\n"); - ret = false; - } - break; } pwdlastset_old = pwdlastset_new; @@ -3095,31 +3337,54 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, case 23: case 25: - /* if no password has been changed, old and new pwdlastset + /* SAMR_FIELD_EXPIRED_FLAG has not been set and no + * password has been changed, old and new pwdlastset * need to be the same value */ - if (!((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) || + if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) && + !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) || (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT))) { torture_assert_int_equal(tctx, pwdlastset_old, pwdlastset_new, "pwdlastset must be equal"); break; } + break; default: if (pwdlastset_old >= pwdlastset_new) { torture_warning(tctx, "pwdLastSet test failed: " - "expected last pwdlastset (%lld) < new pwdlastset (%lld)\n", - pwdlastset_old, pwdlastset_new); + "expected last pwdlastset (%llu) < new pwdlastset (%llu)\n", + (unsigned long long) pwdlastset_old, + (unsigned long long) pwdlastset_new); ret = false; } if (pwdlastset_new == 0) { torture_warning(tctx, "pwdLastSet test failed: " - "expected non-0 pwdlastset, got: %lld\n", - pwdlastset_new); + "expected non-0 pwdlastset, got: %llu\n", + (unsigned long long) pwdlastset_new); + ret = false; + } + break; + } + + switch (levels[l]) { + case 21: + case 23: + case 25: + if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) || + (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) && + (pwdlastset_old > 0) && (pwdlastset_new > 0) && + (pwdlastset_old >= pwdlastset_new)) { + torture_warning(tctx, "pwdlastset not increasing\n"); ret = false; } + break; } + pwdlastset_old = pwdlastset_new; + + usleep(delay); + /* set #3 */ /* set a password and force password change (pwdlastset 0) by @@ -3168,19 +3433,12 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, pwdlastset_new, "pwdlastset must be equal"); break; } + break; default: - - if (pwdlastset_old == pwdlastset_new) { - torture_warning(tctx, "pwdLastSet test failed: " - "expected last pwdlastset (%lld) != new pwdlastset (%lld)\n", - pwdlastset_old, pwdlastset_new); - ret = false; - } - if (pwdlastset_new != 0) { torture_warning(tctx, "pwdLastSet test failed: " - "expected pwdLastSet 0, got %lld\n", - pwdlastset_old); + "expected pwdLastSet 0, got %llu\n", + (unsigned long long) pwdlastset_old); ret = false; } break; @@ -3198,13 +3456,6 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, ret = false; } break; - default: - if ((pwdlastset_old > 0) && (pwdlastset_new > 0) && - (pwdlastset_old >= pwdlastset_new)) { - torture_warning(tctx, "pwdlastset not increasing\n"); - ret = false; - } - break; } /* if the level we are testing does not have a fields_present @@ -3231,62 +3482,1142 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p, #undef TEST_SET_LEVELS #undef TEST_QUERY_LEVELS + talloc_free(np); + return ret; } -static bool test_user_ops(struct dcerpc_pipe *p, - struct torture_context *tctx, - struct policy_handle *user_handle, - struct policy_handle *domain_handle, - uint32_t base_acct_flags, - const char *base_acct_name, enum torture_samr_choice which_ops, - struct cli_credentials *machine_credentials) +static bool test_QueryUserInfo_badpwdcount(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle, + uint32_t *badpwdcount) { - char *password = NULL; - struct samr_QueryUserInfo q; union samr_UserInfo *info; - NTSTATUS status; + struct samr_QueryUserInfo r; - bool ret = true; - int i; - uint32_t rid; - const uint32_t password_fields[] = { - SAMR_FIELD_NT_PASSWORD_PRESENT, - SAMR_FIELD_LM_PASSWORD_PRESENT, - SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT, - 0 - }; - - status = test_LookupName(p, tctx, domain_handle, base_acct_name, &rid); - if (!NT_STATUS_IS_OK(status)) { - ret = false; - } + r.in.user_handle = handle; + r.in.level = 3; + r.out.info = &info; - switch (which_ops) { - case TORTURE_SAMR_USER_ATTRIBUTES: - if (!test_QuerySecurity(p, tctx, user_handle)) { - ret = false; - } + torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level); - if (!test_QueryUserInfo(p, tctx, user_handle)) { - ret = false; - } + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r), + "failed to query userinfo"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to query userinfo"); - if (!test_QueryUserInfo2(p, tctx, user_handle)) { - ret = false; - } + *badpwdcount = info->info3.bad_password_count; - if (!test_SetUserInfo(p, tctx, user_handle, base_acct_flags, - base_acct_name)) { - ret = false; - } + torture_comment(tctx, " (bad password count: %d)\n", *badpwdcount); - if (!test_GetUserPwInfo(p, tctx, user_handle)) { - ret = false; - } + return true; +} - if (!test_TestPrivateFunctionsUser(p, tctx, user_handle)) { - ret = false; +static bool test_SetUserInfo_acct_flags(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *user_handle, + uint32_t acct_flags) +{ + struct samr_SetUserInfo r; + union samr_UserInfo user_info; + + torture_comment(tctx, "Testing SetUserInfo level 16\n"); + + user_info.info16.acct_flags = acct_flags; + + r.in.user_handle = user_handle; + r.in.level = 16; + r.in.info = &user_info; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &r), + "failed to set account flags"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to set account flags"); + + return true; +} + +static bool test_reset_badpwdcount(struct dcerpc_pipe *p, + struct torture_context *tctx, + struct policy_handle *user_handle, + uint32_t acct_flags, + char **password) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + + torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password), + "failed to set password"); + + torture_comment(tctx, "Testing SetUserInfo level 16 (enable account)\n"); + + torture_assert(tctx, + test_SetUserInfo_acct_flags(b, tctx, user_handle, + acct_flags & ~ACB_DISABLED), + "failed to enable user"); + + torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password), + "failed to set password"); + + return true; +} + +static bool test_SetDomainInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + enum samr_DomainInfoClass level, + union samr_DomainInfo *info) +{ + struct samr_SetDomainInfo r; + + r.in.domain_handle = domain_handle; + r.in.level = level; + r.in.info = info; + + torture_assert_ntstatus_ok(tctx, + dcerpc_samr_SetDomainInfo_r(b, tctx, &r), + "failed to set domain info"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to set domain info"); + + return true; +} + +static bool test_SetDomainInfo_ntstatus(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + enum samr_DomainInfoClass level, + union samr_DomainInfo *info, + NTSTATUS expected) +{ + struct samr_SetDomainInfo r; + + r.in.domain_handle = domain_handle; + r.in.level = level; + r.in.info = info; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &r), + "SetDomainInfo failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, expected, ""); + + return true; +} + +static bool test_QueryDomainInfo2_level(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + enum samr_DomainInfoClass level, + union samr_DomainInfo **q_info) +{ + struct samr_QueryDomainInfo2 r; + + r.in.domain_handle = domain_handle; + r.in.level = level; + r.out.info = q_info; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo2_r(b, tctx, &r), + "failed to query domain info"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to query domain info"); + + return true; +} + +static bool test_Password_badpwdcount(struct dcerpc_pipe *p, + struct dcerpc_pipe *np, + struct torture_context *tctx, + uint32_t acct_flags, + const char *acct_name, + struct policy_handle *domain_handle, + struct policy_handle *user_handle, + char **password, + struct cli_credentials *machine_credentials, + const char *comment, + bool disable, + bool interactive, + NTSTATUS expected_success_status, + struct samr_DomInfo1 *info1, + struct samr_DomInfo12 *info12) +{ + union samr_DomainInfo info; + char **passwords; + int i; + uint32_t badpwdcount, tmp; + uint32_t password_history_length = 12; + uint32_t lockout_threshold = 15; + struct dcerpc_binding_handle *b = p->binding_handle; + + torture_comment(tctx, "\nTesting bad pwd count with: %s\n", comment); + + torture_assert(tctx, password_history_length < lockout_threshold, + "password history length needs to be smaller than account lockout threshold for this test"); + + + /* set policies */ + + info.info1 = *info1; + info.info1.password_history_length = password_history_length; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainPasswordInformation, &info), + "failed to set password history length"); + + info.info12 = *info12; + info.info12.lockout_threshold = lockout_threshold; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainLockoutInformation, &info), + "failed to set lockout threshold"); + + /* reset bad pwd count */ + + torture_assert(tctx, + test_reset_badpwdcount(p, tctx, user_handle, acct_flags, password), ""); + + + /* enable or disable account */ + if (disable) { + torture_assert(tctx, + test_SetUserInfo_acct_flags(b, tctx, user_handle, + acct_flags | ACB_DISABLED), + "failed to disable user"); + } else { + torture_assert(tctx, + test_SetUserInfo_acct_flags(b, tctx, user_handle, + acct_flags & ~ACB_DISABLED), + "failed to enable user"); + } + + + /* setup password history */ + + passwords = talloc_array(tctx, char *, password_history_length); + + for (i=0; i < password_history_length; i++) { + + torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password), + "failed to set password"); + passwords[i] = talloc_strdup(tctx, *password); + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, passwords[i], + expected_success_status, interactive)) { + torture_fail(tctx, "failed to auth with latest password"); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + + torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0"); + } + + + /* test with wrong password */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, "random_crap", + NT_STATUS_WRONG_PASSWORD, interactive)) { + torture_fail(tctx, "succeeded to authenticate with wrong password"); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + + torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1"); + + + /* test with latest good password */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name, + passwords[password_history_length-1], + expected_success_status, interactive)) { + torture_fail(tctx, "succeeded to authenticate with wrong password"); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + + if (disable) { + torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1"); + } else { + /* only enabled accounts get the bad pwd count reset upon + * successful logon */ + torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0"); + } + + tmp = badpwdcount; + + + /* test password history */ + + for (i=0; i < password_history_length; i++) { + + torture_comment(tctx, "Testing bad password count behavior with " + "password #%d of #%d\n", i, password_history_length); + + /* - network samlogon will succeed auth and not + * increase badpwdcount for 2 last entries + * - interactive samlogon only for the last one */ + + if (i == password_history_length - 1 || + (i == password_history_length - 2 && !interactive)) { + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, passwords[i], + expected_success_status, interactive)) { + torture_fail(tctx, talloc_asprintf(tctx, "succeeded to authenticate with old password (#%d of #%d in history)", i, password_history_length)); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + + if (disable) { + /* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE* for pwd history entry %d\n", i); */ + torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount"); + } else { + /* torture_comment(tctx, "expecting bad pwd count to be 0 for pwd history entry %d\n", i); */ + torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0"); + } + + tmp = badpwdcount; + + continue; + } + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, passwords[i], + NT_STATUS_WRONG_PASSWORD, interactive)) { + torture_fail(tctx, talloc_asprintf(tctx, "succeeded to authenticate with old password (#%d of #%d in history)", i, password_history_length)); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + + /* - network samlogon will fail auth but not increase + * badpwdcount for 3rd last entry + * - interactive samlogon for 3rd and 2nd last entry */ + + if (i == password_history_length - 3 || + (i == password_history_length - 2 && interactive)) { + /* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE * by one for pwd history entry %d\n", i); */ + torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount"); + } else { + /* torture_comment(tctx, "expecting bad pwd count to increase by one for pwd history entry %d\n", i); */ + torture_assert_int_equal(tctx, badpwdcount, tmp + 1, "unexpected badpwdcount"); + } + + tmp = badpwdcount; + } + + return true; +} + +static bool test_Password_badpwdcount_wrap(struct dcerpc_pipe *p, + struct torture_context *tctx, + uint32_t acct_flags, + const char *acct_name, + struct policy_handle *domain_handle, + struct policy_handle *user_handle, + char **password, + struct cli_credentials *machine_credentials) +{ + union samr_DomainInfo *q_info, s_info; + struct samr_DomInfo1 info1, _info1; + struct samr_DomInfo12 info12, _info12; + bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *np; + int i; + + struct { + const char *comment; + bool disabled; + bool interactive; + NTSTATUS expected_success_status; + } creds[] = { + { + .comment = "network logon (disabled account)", + .disabled = true, + .interactive = false, + .expected_success_status= NT_STATUS_ACCOUNT_DISABLED + }, + { + .comment = "network logon (enabled account)", + .disabled = false, + .interactive = false, + .expected_success_status= NT_STATUS_OK + }, + { + .comment = "interactive logon (disabled account)", + .disabled = true, + .interactive = true, + .expected_success_status= NT_STATUS_ACCOUNT_DISABLED + }, + { + .comment = "interactive logon (enabled account)", + .disabled = false, + .interactive = true, + .expected_success_status= NT_STATUS_OK + }, + }; + + torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), ""); + + /* backup old policies */ + + torture_assert(tctx, + test_QueryDomainInfo2_level(b, tctx, domain_handle, + DomainPasswordInformation, &q_info), + "failed to query domain info level 1"); + + info1 = q_info->info1; + _info1 = info1; + + torture_assert(tctx, + test_QueryDomainInfo2_level(b, tctx, domain_handle, + DomainLockoutInformation, &q_info), + "failed to query domain info level 12"); + + info12 = q_info->info12; + _info12 = info12; + + /* run tests */ + + for (i=0; i < ARRAY_SIZE(creds); i++) { + + /* skip trust tests for now */ + if (acct_flags & ACB_WSTRUST || + acct_flags & ACB_SVRTRUST || + acct_flags & ACB_DOMTRUST) { + continue; + } + + ret &= test_Password_badpwdcount(p, np, tctx, acct_flags, acct_name, + domain_handle, user_handle, password, + machine_credentials, + creds[i].comment, + creds[i].disabled, + creds[i].interactive, + creds[i].expected_success_status, + &_info1, &_info12); + if (!ret) { + torture_warning(tctx, "TEST #%d (%s) failed\n", i, creds[i].comment); + } else { + torture_comment(tctx, "TEST #%d (%s) succeeded\n", i, creds[i].comment); + } + } + + /* restore policies */ + + s_info.info1 = info1; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainPasswordInformation, &s_info), + "failed to set password information"); + + s_info.info12 = info12; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainLockoutInformation, &s_info), + "failed to set lockout information"); + + return ret; +} + +static bool test_QueryUserInfo_acct_flags(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle, + uint32_t *acct_flags) +{ + union samr_UserInfo *info; + struct samr_QueryUserInfo r; + + r.in.user_handle = handle; + r.in.level = 16; + r.out.info = &info; + + torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r), + "failed to query userinfo"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to query userinfo"); + + *acct_flags = info->info16.acct_flags; + + torture_comment(tctx, " (acct_flags: 0x%08x)\n", *acct_flags); + + return true; +} + +static bool test_Password_lockout(struct dcerpc_pipe *p, + struct dcerpc_pipe *np, + struct torture_context *tctx, + uint32_t acct_flags, + const char *acct_name, + struct policy_handle *domain_handle, + struct policy_handle *user_handle, + char **password, + struct cli_credentials *machine_credentials, + const char *comment, + bool disable, + bool interactive, + NTSTATUS expected_success_status, + struct samr_DomInfo1 *info1, + struct samr_DomInfo12 *info12) +{ + union samr_DomainInfo info; + uint32_t badpwdcount; + uint32_t password_history_length = 1; + uint64_t lockout_threshold = 1; + uint32_t lockout_seconds = 5; + uint64_t delta_time_factor = 10 * 1000 * 1000; + struct dcerpc_binding_handle *b = p->binding_handle; + + torture_comment(tctx, "\nTesting account lockout: %s\n", comment); + + /* set policies */ + + info.info1 = *info1; + + torture_comment(tctx, "setting password history length.\n"); + info.info1.password_history_length = password_history_length; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainPasswordInformation, &info), + "failed to set password history length"); + + info.info12 = *info12; + info.info12.lockout_threshold = lockout_threshold; + + /* set lockout duration < lockout window: should fail */ + info.info12.lockout_duration = ~(lockout_seconds * delta_time_factor); + info.info12.lockout_window = ~((lockout_seconds + 1) * delta_time_factor); + + torture_assert(tctx, + test_SetDomainInfo_ntstatus(b, tctx, domain_handle, + DomainLockoutInformation, &info, + NT_STATUS_INVALID_PARAMETER), + "setting lockout duration < lockout window gave unexpected result"); + + info.info12.lockout_duration = 0; + info.info12.lockout_window = 0; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainLockoutInformation, &info), + "failed to set lockout window and duration to 0"); + + + /* set lockout duration of 5 seconds */ + info.info12.lockout_duration = ~(lockout_seconds * delta_time_factor); + info.info12.lockout_window = ~(lockout_seconds * delta_time_factor); + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainLockoutInformation, &info), + "failed to set lockout window and duration to 5 seconds"); + + /* reset bad pwd count */ + + torture_assert(tctx, + test_reset_badpwdcount(p, tctx, user_handle, acct_flags, password), ""); + + + /* enable or disable account */ + + if (disable) { + torture_assert(tctx, + test_SetUserInfo_acct_flags(b, tctx, user_handle, + acct_flags | ACB_DISABLED), + "failed to disable user"); + } else { + torture_assert(tctx, + test_SetUserInfo_acct_flags(b, tctx, user_handle, + acct_flags & ~ACB_DISABLED), + "failed to enable user"); + } + + + /* test logon with right password */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, *password, + expected_success_status, interactive)) { + torture_fail(tctx, "failed to auth with latest password"); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0"); + + + /* test with wrong password ==> lockout */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, "random_crap", + NT_STATUS_WRONG_PASSWORD, interactive)) { + torture_fail(tctx, "succeeded to authenticate with wrong password"); + } + + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1"); + + torture_assert(tctx, + test_QueryUserInfo_acct_flags(b, tctx, user_handle, &acct_flags), ""); + torture_assert_int_equal(tctx, acct_flags & ACB_AUTOLOCK, 0, + "expected account to be locked"); + + + /* test with good password */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name, + *password, + NT_STATUS_ACCOUNT_LOCKED_OUT, interactive)) + { + torture_fail(tctx, "authenticate did not return NT_STATUS_ACCOUNT_LOCKED_OUT"); + } + + /* bad pwd count should not get updated */ + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1"); + + /* curiously, windows does _not_ set the autlock flag */ + torture_assert(tctx, + test_QueryUserInfo_acct_flags(b, tctx, user_handle, &acct_flags), ""); + torture_assert_int_equal(tctx, acct_flags & ACB_AUTOLOCK, 0, + "expected account to be locked"); + + + /* with bad password */ + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, + acct_name, "random_crap2", + NT_STATUS_ACCOUNT_LOCKED_OUT, interactive)) + { + torture_fail(tctx, "authenticate did not return NT_STATUS_ACCOUNT_LOCKED_OUT"); + } + + /* bad pwd count should not get updated */ + torture_assert(tctx, + test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), ""); + torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1"); + + /* curiously, windows does _not_ set the autlock flag */ + torture_assert(tctx, + test_QueryUserInfo_acct_flags(b, tctx, user_handle, &acct_flags), ""); + torture_assert_int_equal(tctx, acct_flags & ACB_AUTOLOCK, 0, + "expected account to be locked"); + + + /* let lockout duration expire ==> unlock */ + + torture_comment(tctx, "let lockout duration expire...\n"); + sleep(lockout_seconds + 1); + + if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name, + *password, + expected_success_status, interactive)) + { + torture_fail(tctx, "failed to authenticate after lockout expired"); + } + + torture_assert(tctx, + test_QueryUserInfo_acct_flags(b, tctx, user_handle, &acct_flags), ""); + torture_assert_int_equal(tctx, acct_flags & ACB_AUTOLOCK, 0, + "expected account not to be locked"); + + return true; +} + +static bool test_Password_lockout_wrap(struct dcerpc_pipe *p, + struct torture_context *tctx, + uint32_t acct_flags, + const char *acct_name, + struct policy_handle *domain_handle, + struct policy_handle *user_handle, + char **password, + struct cli_credentials *machine_credentials) +{ + union samr_DomainInfo *q_info, s_info; + struct samr_DomInfo1 info1, _info1; + struct samr_DomInfo12 info12, _info12; + bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_pipe *np; + int i; + + struct { + const char *comment; + bool disabled; + bool interactive; + NTSTATUS expected_success_status; + } creds[] = { + { + .comment = "network logon (disabled account)", + .disabled = true, + .interactive = false, + .expected_success_status= NT_STATUS_ACCOUNT_DISABLED + }, + { + .comment = "network logon (enabled account)", + .disabled = false, + .interactive = false, + .expected_success_status= NT_STATUS_OK + }, + { + .comment = "interactive logon (disabled account)", + .disabled = true, + .interactive = true, + .expected_success_status= NT_STATUS_ACCOUNT_DISABLED + }, + { + .comment = "interactive logon (enabled account)", + .disabled = false, + .interactive = true, + .expected_success_status= NT_STATUS_OK + }, + }; + + torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), ""); + + /* backup old policies */ + + torture_assert(tctx, + test_QueryDomainInfo2_level(b, tctx, domain_handle, + DomainPasswordInformation, &q_info), + "failed to query domain info level 1"); + + info1 = q_info->info1; + _info1 = info1; + + torture_assert(tctx, + test_QueryDomainInfo2_level(b, tctx, domain_handle, + DomainLockoutInformation, &q_info), + "failed to query domain info level 12"); + + info12 = q_info->info12; + _info12 = info12; + + /* run tests */ + + for (i=0; i < ARRAY_SIZE(creds); i++) { + + /* skip trust tests for now */ + if (acct_flags & ACB_WSTRUST || + acct_flags & ACB_SVRTRUST || + acct_flags & ACB_DOMTRUST) { + continue; + } + + ret &= test_Password_lockout(p, np, tctx, acct_flags, acct_name, + domain_handle, user_handle, password, + machine_credentials, + creds[i].comment, + creds[i].disabled, + creds[i].interactive, + creds[i].expected_success_status, + &_info1, &_info12); + if (!ret) { + torture_warning(tctx, "TEST #%d (%s) failed\n", i, creds[i].comment); + } else { + torture_comment(tctx, "TEST #%d (%s) succeeded\n", i, creds[i].comment); + } + } + + /* restore policies */ + + s_info.info1 = info1; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainPasswordInformation, &s_info), + "failed to set password information"); + + s_info.info12 = info12; + + torture_assert(tctx, + test_SetDomainInfo(b, tctx, domain_handle, + DomainLockoutInformation, &s_info), + "failed to set lockout information"); + + return ret; +} + +static bool test_DeleteUser_with_privs(struct dcerpc_pipe *p, + struct dcerpc_pipe *lp, + struct torture_context *tctx, + struct policy_handle *domain_handle, + struct policy_handle *lsa_handle, + struct policy_handle *user_handle, + const struct dom_sid *domain_sid, + uint32_t rid, + struct cli_credentials *machine_credentials) +{ + bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_binding_handle *lb = lp->binding_handle; + + struct policy_handle lsa_acct_handle; + struct dom_sid *user_sid; + + user_sid = dom_sid_add_rid(tctx, domain_sid, rid); + + { + struct lsa_EnumAccountRights r; + struct lsa_RightSet rights; + + torture_comment(tctx, "Testing LSA EnumAccountRights\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.out.rights = &rights; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r), + "lsa_EnumAccountRights failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND, + "Expected enum rights for account to fail"); + } + + { + struct lsa_RightSet rights; + struct lsa_StringLarge names[2]; + struct lsa_AddAccountRights r; + + torture_comment(tctx, "Testing LSA AddAccountRights\n"); + + init_lsa_StringLarge(&names[0], "SeMachineAccountPrivilege"); + init_lsa_StringLarge(&names[1], NULL); + + rights.count = 1; + rights.names = names; + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.in.rights = &rights; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_AddAccountRights_r(lb, tctx, &r), + "lsa_AddAccountRights failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to add privileges"); + } + + { + struct lsa_EnumAccounts r; + uint32_t resume_handle = 0; + struct lsa_SidArray lsa_sid_array; + int i; + bool found_sid = false; + + torture_comment(tctx, "Testing LSA EnumAccounts\n"); + + r.in.handle = lsa_handle; + r.in.num_entries = 0x1000; + r.in.resume_handle = &resume_handle; + r.out.sids = &lsa_sid_array; + r.out.resume_handle = &resume_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r), + "lsa_EnumAccounts failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to enum accounts"); + + for (i=0; i < lsa_sid_array.num_sids; i++) { + if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) { + found_sid = true; + } + } + + torture_assert(tctx, found_sid, + "failed to list privileged account"); + } + + { + struct lsa_EnumAccountRights r; + struct lsa_RightSet user_rights; + + torture_comment(tctx, "Testing LSA EnumAccountRights\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.out.rights = &user_rights; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r), + "lsa_EnumAccountRights failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to enum rights for account"); + + if (user_rights.count < 1) { + torture_warning(tctx, "failed to find newly added rights"); + return false; + } + } + + { + struct lsa_OpenAccount r; + + torture_comment(tctx, "Testing LSA OpenAccount\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.out.acct_handle = &lsa_acct_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(lb, tctx, &r), + "lsa_OpenAccount failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to open lsa account"); + } + + { + struct lsa_GetSystemAccessAccount r; + uint32_t access_mask; + + torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n"); + + r.in.handle = &lsa_acct_handle; + r.out.access_mask = &access_mask; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetSystemAccessAccount_r(lb, tctx, &r), + "lsa_GetSystemAccessAccount failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to get lsa system access account"); + } + + { + struct lsa_Close r; + + torture_comment(tctx, "Testing LSA Close\n"); + + r.in.handle = &lsa_acct_handle; + r.out.handle = &lsa_acct_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Close_r(lb, tctx, &r), + "lsa_Close failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to close lsa"); + } + + { + struct samr_DeleteUser r; + + torture_comment(tctx, "Testing SAMR DeleteUser\n"); + + r.in.user_handle = user_handle; + r.out.user_handle = user_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &r), + "DeleteUser failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "DeleteUser failed"); + } + + { + struct lsa_EnumAccounts r; + uint32_t resume_handle = 0; + struct lsa_SidArray lsa_sid_array; + int i; + bool found_sid = false; + + torture_comment(tctx, "Testing LSA EnumAccounts\n"); + + r.in.handle = lsa_handle; + r.in.num_entries = 0x1000; + r.in.resume_handle = &resume_handle; + r.out.sids = &lsa_sid_array; + r.out.resume_handle = &resume_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r), + "lsa_EnumAccounts failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to enum accounts"); + + for (i=0; i < lsa_sid_array.num_sids; i++) { + if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) { + found_sid = true; + } + } + + torture_assert(tctx, found_sid, + "failed to list privileged account"); + } + + { + struct lsa_EnumAccountRights r; + struct lsa_RightSet user_rights; + + torture_comment(tctx, "Testing LSA EnumAccountRights\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.out.rights = &user_rights; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r), + "lsa_EnumAccountRights failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to enum rights for account"); + + if (user_rights.count < 1) { + torture_warning(tctx, "failed to find newly added rights"); + return false; + } + } + + { + struct lsa_OpenAccount r; + + torture_comment(tctx, "Testing LSA OpenAccount\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.out.acct_handle = &lsa_acct_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(lb, tctx, &r), + "lsa_OpenAccount failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to open lsa account"); + } + + { + struct lsa_GetSystemAccessAccount r; + uint32_t access_mask; + + torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n"); + + r.in.handle = &lsa_acct_handle; + r.out.access_mask = &access_mask; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetSystemAccessAccount_r(lb, tctx, &r), + "lsa_GetSystemAccessAccount failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to get lsa system access account"); + } + + { + struct lsa_DeleteObject r; + + torture_comment(tctx, "Testing LSA DeleteObject\n"); + + r.in.handle = &lsa_acct_handle; + r.out.handle = &lsa_acct_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_DeleteObject_r(lb, tctx, &r), + "lsa_DeleteObject failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to delete object"); + } + + { + struct lsa_EnumAccounts r; + uint32_t resume_handle = 0; + struct lsa_SidArray lsa_sid_array; + int i; + bool found_sid = false; + + torture_comment(tctx, "Testing LSA EnumAccounts\n"); + + r.in.handle = lsa_handle; + r.in.num_entries = 0x1000; + r.in.resume_handle = &resume_handle; + r.out.sids = &lsa_sid_array; + r.out.resume_handle = &resume_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r), + "lsa_EnumAccounts failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "Failed to enum accounts"); + + for (i=0; i < lsa_sid_array.num_sids; i++) { + if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) { + found_sid = true; + } + } + + torture_assert(tctx, !found_sid, + "should not have listed privileged account"); + } + + { + struct lsa_EnumAccountRights r; + struct lsa_RightSet user_rights; + + torture_comment(tctx, "Testing LSA EnumAccountRights\n"); + + r.in.handle = lsa_handle; + r.in.sid = user_sid; + r.out.rights = &user_rights; + + torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r), + "lsa_EnumAccountRights failed"); + torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND, + "Failed to enum rights for account"); + } + + return ret; +} + +static bool test_user_ops(struct dcerpc_pipe *p, + struct torture_context *tctx, + struct policy_handle *user_handle, + struct policy_handle *domain_handle, + const struct dom_sid *domain_sid, + uint32_t base_acct_flags, + const char *base_acct_name, enum torture_samr_choice which_ops, + struct cli_credentials *machine_credentials) +{ + char *password = NULL; + struct samr_QueryUserInfo q; + union samr_UserInfo *info; + NTSTATUS status; + struct dcerpc_binding_handle *b = p->binding_handle; + + bool ret = true; + int i; + uint32_t rid; + const uint32_t password_fields[] = { + SAMR_FIELD_NT_PASSWORD_PRESENT, + SAMR_FIELD_LM_PASSWORD_PRESENT, + SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT, + 0 + }; + + status = test_LookupName(b, 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(b, tctx, user_handle)) { + ret = false; + } + + if (!test_QueryUserInfo(b, tctx, user_handle)) { + ret = false; + } + + if (!test_QueryUserInfo2(b, tctx, user_handle)) { + ret = false; + } + + if (!test_SetUserInfo(b, tctx, user_handle, base_acct_flags, + base_acct_name)) { + ret = false; + } + + if (!test_GetUserPwInfo(b, tctx, user_handle)) { + ret = false; + } + + if (!test_TestPrivateFunctionsUser(b, tctx, user_handle)) { + ret = false; } if (!test_SetUserPass(p, tctx, user_handle, &password)) { @@ -3297,11 +4628,11 @@ static bool test_user_ops(struct dcerpc_pipe *p, if (base_acct_flags & (ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) { char simple_pass[9]; char *v = generate_random_str(tctx, 1); - + ZERO_STRUCT(simple_pass); memset(simple_pass, *v, sizeof(simple_pass) - 1); - printf("Testing machine account password policy rules\n"); + torture_comment(tctx, "Testing machine account password policy rules\n"); /* Workstation trust accounts don't seem to need to honour password quality policy */ if (!test_SetUserPassEx(p, tctx, user_handle, true, &password)) { @@ -3331,83 +4662,82 @@ static bool test_user_ops(struct dcerpc_pipe *p, for (i = 0; password_fields[i]; i++) { if (!test_SetUserPass_23(p, tctx, user_handle, password_fields[i], &password)) { ret = false; - } - + } + /* check it was set right */ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { ret = false; } - } + } for (i = 0; password_fields[i]; i++) { if (!test_SetUserPass_25(p, tctx, user_handle, password_fields[i], &password)) { ret = false; - } - + } + /* check it was set right */ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { ret = false; } - } + } if (!test_SetUserPassEx(p, tctx, user_handle, false, &password)) { ret = false; - } + } if (!test_ChangePassword(p, tctx, base_acct_name, domain_handle, &password)) { ret = false; - } + } - if (torture_setting_bool(tctx, "samba4", false)) { - printf("skipping Set Password level 18 and 21 against Samba4\n"); - } else { + if (!test_SetUserPass_18(p, tctx, user_handle, &password)) { + ret = false; + } - if (!test_SetUserPass_18(p, tctx, user_handle, &password)) { - ret = false; + if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { + ret = false; + } + + for (i = 0; password_fields[i]; i++) { + + if (password_fields[i] == SAMR_FIELD_LM_PASSWORD_PRESENT) { + /* we need to skip as that would break + * the ChangePasswordUser3 verify */ + continue; } - if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { + if (!test_SetUserPass_21(p, tctx, user_handle, password_fields[i], &password)) { ret = false; } - for (i = 0; password_fields[i]; i++) { - - if (password_fields[i] == SAMR_FIELD_LM_PASSWORD_PRESENT) { - /* we need to skip as that would break - * the ChangePasswordUser3 verify */ - continue; - } - - if (!test_SetUserPass_21(p, tctx, user_handle, password_fields[i], &password)) { - ret = false; - } - - /* check it was set right */ - if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { - ret = false; - } + /* check it was set right */ + if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) { + ret = false; } } q.in.user_handle = user_handle; q.in.level = 5; q.out.info = &info; - - 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)); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q), + "QueryUserInfo failed"); + if (!NT_STATUS_IS_OK(q.out.result)) { + torture_warning(tctx, "QueryUserInfo level %u failed - %s\n", + q.in.level, nt_errstr(q.out.result)); ret = false; } else { uint32_t expected_flags = (base_acct_flags | ACB_PWNOTREQ | ACB_DISABLED); if ((info->info5.acct_flags) != expected_flags) { - printf("QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", + torture_warning(tctx, "QueryUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", info->info5.acct_flags, expected_flags); - ret = false; + /* FIXME: GD */ + if (!torture_setting_bool(tctx, "samba3", false)) { + ret = false; + } } if (info->info5.rid != rid) { - printf("QuerUserInfo level 5 failed, it returned %u when we expected rid of %u\n", + torture_warning(tctx, "QueryUserInfo level 5 failed, it returned %u when we expected rid of %u\n", info->info5.rid, rid); } @@ -3433,41 +4763,118 @@ static bool test_user_ops(struct dcerpc_pipe *p, break; + case TORTURE_SAMR_PASSWORDS_BADPWDCOUNT: + + /* test bad pwd count change behaviour */ + if (!test_Password_badpwdcount_wrap(p, tctx, base_acct_flags, + base_acct_name, + domain_handle, + user_handle, &password, + machine_credentials)) { + ret = false; + } + + if (ret == true) { + torture_comment(tctx, "badPwdCount test succeeded\n"); + } else { + torture_warning(tctx, "badPwdCount test failed\n"); + } + + break; + + case TORTURE_SAMR_PASSWORDS_LOCKOUT: + + if (!test_Password_lockout_wrap(p, tctx, base_acct_flags, + base_acct_name, + domain_handle, + user_handle, &password, + machine_credentials)) + { + ret = false; + } + + if (ret == true) { + torture_comment(tctx, "lockout test succeeded\n"); + } else { + torture_warning(tctx, "lockout test failed\n"); + } + + break; + + + case TORTURE_SAMR_USER_PRIVILEGES: { + + struct dcerpc_pipe *lp; + struct policy_handle *lsa_handle; + struct dcerpc_binding_handle *lb; + + status = torture_rpc_connection(tctx, &lp, &ndr_table_lsarpc); + torture_assert_ntstatus_ok(tctx, status, "Failed to open LSA pipe"); + lb = lp->binding_handle; + + if (!test_lsa_OpenPolicy2(lb, tctx, &lsa_handle)) { + ret = false; + } + + if (!test_DeleteUser_with_privs(p, lp, tctx, + domain_handle, lsa_handle, user_handle, + domain_sid, rid, + machine_credentials)) { + ret = false; + } + + if (!test_lsa_Close(lb, tctx, lsa_handle)) { + ret = false; + } + + if (!ret) { + torture_warning(tctx, "privileged user delete test failed\n"); + } + + break; + } case TORTURE_SAMR_OTHER: + case TORTURE_SAMR_MANY_ACCOUNTS: + case TORTURE_SAMR_MANY_GROUPS: + case TORTURE_SAMR_MANY_ALIASES: /* We just need the account to exist */ break; } return ret; } -static bool test_alias_ops(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_alias_ops(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *alias_handle, const struct dom_sid *domain_sid) { bool ret = true; - if (!test_QuerySecurity(p, tctx, alias_handle)) { - ret = false; + if (!torture_setting_bool(tctx, "samba3", false)) { + if (!test_QuerySecurity(b, tctx, alias_handle)) { + ret = false; + } } - if (!test_QueryAliasInfo(p, tctx, alias_handle)) { + if (!test_QueryAliasInfo(b, tctx, alias_handle)) { ret = false; } - if (!test_SetAliasInfo(p, tctx, alias_handle)) { + if (!test_SetAliasInfo(b, tctx, alias_handle)) { ret = false; } - if (!test_AddMemberToAlias(p, tctx, alias_handle, domain_sid)) { + if (!test_AddMemberToAlias(b, tctx, alias_handle, domain_sid)) { ret = false; } - if (torture_setting_bool(tctx, "samba4", false)) { - printf("skipping MultipleMembers Alias tests against Samba4\n"); + if (torture_setting_bool(tctx, "samba3", false) || + torture_setting_bool(tctx, "samba4", false)) { + torture_comment(tctx, "skipping MultipleMembers Alias tests against Samba\n"); return ret; } - if (!test_AddMultipleMembersToAlias(p, tctx, alias_handle)) { + if (!test_AddMultipleMembersToAlias(b, tctx, alias_handle)) { ret = false; } @@ -3475,23 +4882,25 @@ static bool test_alias_ops(struct dcerpc_pipe *p, struct torture_context *tctx, } -static bool test_DeleteUser(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *user_handle) +static bool test_DeleteUser(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *user_handle) { struct samr_DeleteUser d; - NTSTATUS status; torture_comment(tctx, "Testing DeleteUser\n"); d.in.user_handle = user_handle; d.out.user_handle = user_handle; - status = dcerpc_samr_DeleteUser(p, tctx, &d); - torture_assert_ntstatus_ok(tctx, status, "DeleteUser"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &d), + "DeleteUser failed"); + torture_assert_ntstatus_ok(tctx, d.out.result, "DeleteUser"); return true; } -bool test_DeleteUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +bool test_DeleteUser_byname(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle, const char *name) { NTSTATUS status; @@ -3499,32 +4908,35 @@ bool test_DeleteUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle user_handle; uint32_t rid; - status = test_LookupName(p, mem_ctx, handle, name, &rid); + status = test_LookupName(b, tctx, handle, name, &rid); if (!NT_STATUS_IS_OK(status)) { goto failed; } - status = test_OpenUser_byname(p, mem_ctx, handle, name, &user_handle); + status = test_OpenUser_byname(b, tctx, handle, name, &user_handle); if (!NT_STATUS_IS_OK(status)) { goto failed; } d.in.user_handle = &user_handle; d.out.user_handle = &user_handle; - status = dcerpc_samr_DeleteUser(p, mem_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &d), + "DeleteUser failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + status = d.out.result; goto failed; } return true; failed: - printf("DeleteUser_byname(%s) failed - %s\n", name, nt_errstr(status)); + torture_warning(tctx, "DeleteUser_byname(%s) failed - %s\n", name, nt_errstr(status)); return false; } -static bool test_DeleteGroup_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_DeleteGroup_byname(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle, const char *name) { NTSTATUS status; @@ -3533,7 +4945,7 @@ static bool test_DeleteGroup_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle group_handle; uint32_t rid; - status = test_LookupName(p, mem_ctx, handle, name, &rid); + status = test_LookupName(b, tctx, handle, name, &rid); if (!NT_STATUS_IS_OK(status)) { goto failed; } @@ -3542,28 +4954,34 @@ static bool test_DeleteGroup_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.in.rid = rid; r.out.group_handle = &group_handle; - status = dcerpc_samr_OpenGroup(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r), + "OpenGroup failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + status = r.out.result; goto failed; } d.in.group_handle = &group_handle; d.out.group_handle = &group_handle; - status = dcerpc_samr_DeleteDomainGroup(p, mem_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomainGroup_r(b, tctx, &d), + "DeleteDomainGroup failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + status = d.out.result; goto failed; } return true; failed: - printf("DeleteGroup_byname(%s) failed - %s\n", name, nt_errstr(status)); + torture_warning(tctx, "DeleteGroup_byname(%s) failed - %s\n", name, nt_errstr(status)); return false; } -static bool test_DeleteAlias_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *domain_handle, const char *name) +static bool test_DeleteAlias_byname(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + const char *name) { NTSTATUS status; struct samr_OpenAlias r; @@ -3571,9 +4989,9 @@ static bool test_DeleteAlias_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle alias_handle; uint32_t rid; - printf("testing DeleteAlias_byname\n"); + torture_comment(tctx, "Testing DeleteAlias_byname\n"); - status = test_LookupName(p, mem_ctx, domain_handle, name, &rid); + status = test_LookupName(b, tctx, domain_handle, name, &rid); if (!NT_STATUS_IS_OK(status)) { goto failed; } @@ -3582,133 +5000,149 @@ static bool test_DeleteAlias_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.in.rid = rid; r.out.alias_handle = &alias_handle; - status = dcerpc_samr_OpenAlias(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenAlias_r(b, tctx, &r), + "OpenAlias failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + status = r.out.result; goto failed; } d.in.alias_handle = &alias_handle; d.out.alias_handle = &alias_handle; - status = dcerpc_samr_DeleteDomAlias(p, mem_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomAlias_r(b, tctx, &d), + "DeleteDomAlias failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + status = d.out.result; goto failed; } return true; failed: - printf("DeleteAlias_byname(%s) failed - %s\n", name, nt_errstr(status)); + torture_warning(tctx, "DeleteAlias_byname(%s) failed - %s\n", name, nt_errstr(status)); return false; } -static bool test_DeleteAlias(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *alias_handle) +static bool test_DeleteAlias(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *alias_handle) { struct samr_DeleteDomAlias d; - NTSTATUS status; bool ret = true; - printf("Testing DeleteAlias\n"); + + torture_comment(tctx, "Testing DeleteAlias\n"); d.in.alias_handle = alias_handle; d.out.alias_handle = alias_handle; - status = dcerpc_samr_DeleteDomAlias(p, mem_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { - printf("DeleteAlias failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomAlias_r(b, tctx, &d), + "DeleteDomAlias failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + torture_warning(tctx, "DeleteAlias failed - %s\n", nt_errstr(d.out.result)); ret = false; } return ret; } -static bool test_CreateAlias(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *domain_handle, - struct policy_handle *alias_handle, - const struct dom_sid *domain_sid) +static bool test_CreateAlias(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + const char *alias_name, + struct policy_handle *alias_handle, + const struct dom_sid *domain_sid, + bool test_alias) { - NTSTATUS status; struct samr_CreateDomAlias r; struct lsa_String name; uint32_t rid; bool ret = true; - init_lsa_String(&name, TEST_ALIASNAME); + init_lsa_String(&name, alias_name); r.in.domain_handle = domain_handle; r.in.alias_name = &name; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.alias_handle = alias_handle; r.out.rid = &rid; - printf("Testing CreateAlias (%s)\n", r.in.alias_name->string); + torture_comment(tctx, "Testing CreateAlias (%s)\n", r.in.alias_name->string); - status = dcerpc_samr_CreateDomAlias(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomAlias_r(b, tctx, &r), + "CreateDomAlias failed"); if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { - printf("Server correctly refused create of '%s'\n", r.in.alias_name->string); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) { + torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.alias_name->string); return true; } else { - printf("Server should have refused create of '%s', got %s instead\n", r.in.alias_name->string, - nt_errstr(status)); + torture_warning(tctx, "Server should have refused create of '%s', got %s instead\n", r.in.alias_name->string, + nt_errstr(r.out.result)); return false; } } - if (NT_STATUS_EQUAL(status, NT_STATUS_ALIAS_EXISTS)) { - if (!test_DeleteAlias_byname(p, tctx, domain_handle, r.in.alias_name->string)) { + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ALIAS_EXISTS)) { + if (!test_DeleteAlias_byname(b, tctx, domain_handle, r.in.alias_name->string)) { return false; } - status = dcerpc_samr_CreateDomAlias(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomAlias_r(b, tctx, &r), + "CreateDomAlias failed"); } - if (!NT_STATUS_IS_OK(status)) { - printf("CreateAlias failed - %s\n", nt_errstr(status)); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "CreateAlias failed - %s\n", nt_errstr(r.out.result)); return false; } - if (!test_alias_ops(p, tctx, alias_handle, domain_sid)) { + if (!test_alias) { + return ret; + } + + if (!test_alias_ops(b, tctx, alias_handle, domain_sid)) { ret = false; } return ret; } -static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_ChangePassword(struct dcerpc_pipe *p, + struct torture_context *tctx, const char *acct_name, struct policy_handle *domain_handle, char **password) { bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; if (!*password) { return false; } - if (!test_ChangePasswordUser(p, mem_ctx, acct_name, domain_handle, password)) { + if (!test_ChangePasswordUser(b, tctx, acct_name, domain_handle, password)) { ret = false; } - if (!test_ChangePasswordUser2(p, mem_ctx, acct_name, password, 0, true)) { + if (!test_ChangePasswordUser2(p, tctx, acct_name, password, 0, true)) { ret = false; } - if (!test_OemChangePasswordUser2(p, mem_ctx, acct_name, domain_handle, password)) { + if (!test_OemChangePasswordUser2(p, tctx, acct_name, domain_handle, password)) { ret = false; } /* test what happens when setting the old password again */ - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, *password, 0, true)) { + if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, *password, 0, true)) { ret = false; } { char simple_pass[9]; - char *v = generate_random_str(mem_ctx, 1); + char *v = generate_random_str(tctx, 1); ZERO_STRUCT(simple_pass); memset(simple_pass, *v, sizeof(simple_pass) - 1); /* test what happens when picking a simple password */ - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, simple_pass, 0, true)) { + if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, simple_pass, 0, true)) { ret = false; } } @@ -3721,7 +5155,6 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, uint16_t len_old, len; uint32_t pwd_prop_old; int64_t min_pwd_age_old; - NTSTATUS status; len = 5; @@ -3729,9 +5162,10 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.level = 1; r.out.info = &info; - printf("testing samr_QueryDomainInfo level 1\n"); - status = dcerpc_samr_QueryDomainInfo(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { + torture_comment(tctx, "Testing samr_QueryDomainInfo level 1\n"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r), + "QueryDomainInfo failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { return false; } @@ -3749,32 +5183,33 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, min_pwd_age_old = s.in.info->info1.min_password_age; s.in.info->info1.min_password_age = 0; - printf("testing samr_SetDomainInfo level 1\n"); - status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); - if (!NT_STATUS_IS_OK(status)) { + torture_comment(tctx, "Testing samr_SetDomainInfo level 1\n"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s), + "SetDomainInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { return false; } - printf("calling test_ChangePasswordUser3 with too short password\n"); + torture_comment(tctx, "calling test_ChangePasswordUser3 with too short password\n"); - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, len - 1, password, NULL, 0, true)) { + if (!test_ChangePasswordUser3(p, tctx, acct_name, len - 1, password, NULL, 0, true)) { ret = false; } s.in.info->info1.min_password_length = len_old; s.in.info->info1.password_properties = pwd_prop_old; s.in.info->info1.min_password_age = min_pwd_age_old; - - printf("testing samr_SetDomainInfo level 1\n"); - status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); - if (!NT_STATUS_IS_OK(status)) { + + torture_comment(tctx, "Testing samr_SetDomainInfo level 1\n"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s), + "SetDomainInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { return false; } } { - NTSTATUS status; struct samr_OpenUser r; struct samr_QueryUserInfo q; union samr_UserInfo *info; @@ -3784,14 +5219,15 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, n.in.domain_handle = domain_handle; n.in.num_names = 1; - n.in.names = talloc_array(mem_ctx, struct lsa_String, 1); - n.in.names[0].string = acct_name; + n.in.names = talloc_array(tctx, struct lsa_String, 1); + n.in.names[0].string = acct_name; n.out.rids = &rids; n.out.types = &types; - status = dcerpc_samr_LookupNames(p, mem_ctx, &n); - if (!NT_STATUS_IS_OK(status)) { - printf("LookupNames failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupNames_r(b, tctx, &n), + "LookupNames failed"); + if (!NT_STATUS_IS_OK(n.out.result)) { + torture_warning(tctx, "LookupNames failed - %s\n", nt_errstr(n.out.result)); return false; } @@ -3800,9 +5236,10 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.rid = n.out.rids->ids[0]; r.out.user_handle = &user_handle; - status = dcerpc_samr_OpenUser(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenUser(%u) failed - %s\n", n.out.rids->ids[0], nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r), + "OpenUser failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "OpenUser(%u) failed - %s\n", n.out.rids->ids[0], nt_errstr(r.out.result)); return false; } @@ -3810,15 +5247,16 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, q.in.level = 5; q.out.info = &info; - status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryUserInfo failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q), + "QueryUserInfo failed"); + if (!NT_STATUS_IS_OK(q.out.result)) { + torture_warning(tctx, "QueryUserInfo failed - %s\n", nt_errstr(q.out.result)); return false; } - printf("calling test_ChangePasswordUser3 with too early password change\n"); + torture_comment(tctx, "calling test_ChangePasswordUser3 with too early password change\n"); - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, + if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL, info->info5.last_password_change, true)) { ret = false; } @@ -3826,11 +5264,11 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, /* we change passwords twice - this has the effect of verifying they were changed correctly for the final call */ - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, 0, true)) { + if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL, 0, true)) { ret = false; } - if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, 0, true)) { + if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL, 0, true)) { ret = false; } @@ -3838,16 +5276,17 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *domain_handle, + struct policy_handle *domain_handle, + const char *user_name, struct policy_handle *user_handle_out, - struct dom_sid *domain_sid, + struct dom_sid *domain_sid, enum torture_samr_choice which_ops, - struct cli_credentials *machine_credentials) + struct cli_credentials *machine_credentials, + bool test_user) { TALLOC_CTX *user_ctx; - NTSTATUS status; struct samr_CreateUser r; struct samr_QueryUserInfo q; union samr_UserInfo *info; @@ -3858,10 +5297,11 @@ static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx, const uint32_t acct_flags = ACB_NORMAL; struct lsa_String name; bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; struct policy_handle user_handle; user_ctx = talloc_named(tctx, 0, "test_CreateUser2 per-user context"); - init_lsa_String(&name, TEST_ACCOUNT_NAME); + init_lsa_String(&name, user_name); r.in.domain_handle = domain_handle; r.in.account_name = &name; @@ -3869,76 +5309,90 @@ static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx, r.out.user_handle = &user_handle; r.out.rid = &rid; - printf("Testing CreateUser(%s)\n", r.in.account_name->string); + torture_comment(tctx, "Testing CreateUser(%s)\n", r.in.account_name->string); - status = dcerpc_samr_CreateUser(p, user_ctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser_r(b, user_ctx, &r), + "CreateUser failed"); if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("Server correctly refused create of '%s'\n", r.in.account_name->string); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.account_name->string); return true; } else { - printf("Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, - nt_errstr(status)); + torture_warning(tctx, "Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, + nt_errstr(r.out.result)); return false; } } - if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { - if (!test_DeleteUser_byname(p, user_ctx, domain_handle, r.in.account_name->string)) { + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) { + if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.account_name->string)) { talloc_free(user_ctx); return false; } - status = dcerpc_samr_CreateUser(p, user_ctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser_r(b, user_ctx, &r), + "CreateUser failed"); } - if (!NT_STATUS_IS_OK(status)) { + + if (!NT_STATUS_IS_OK(r.out.result)) { talloc_free(user_ctx); - printf("CreateUser failed - %s\n", nt_errstr(status)); + torture_warning(tctx, "CreateUser failed - %s\n", nt_errstr(r.out.result)); return false; - } else { + } + + if (!test_user) { + if (user_handle_out) { + *user_handle_out = user_handle; + } + return ret; + } + + { q.in.user_handle = &user_handle; q.in.level = 16; q.out.info = &info; - - status = dcerpc_samr_QueryUserInfo(p, user_ctx, &q); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryUserInfo level %u failed - %s\n", - q.in.level, nt_errstr(status)); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, user_ctx, &q), + "QueryUserInfo failed"); + if (!NT_STATUS_IS_OK(q.out.result)) { + torture_warning(tctx, "QueryUserInfo level %u failed - %s\n", + q.in.level, nt_errstr(q.out.result)); ret = false; } else { if ((info->info16.acct_flags & acct_flags) != acct_flags) { - printf("QuerUserInfo level 16 failed, it returned 0x%08x when we expected flags of 0x%08x\n", + torture_warning(tctx, "QueryUserInfo level 16 failed, it returned 0x%08x when we expected flags of 0x%08x\n", info->info16.acct_flags, acct_flags); ret = false; } } - - if (!test_user_ops(p, tctx, &user_handle, domain_handle, - acct_flags, name.string, which_ops, + + if (!test_user_ops(p, tctx, &user_handle, domain_handle, + domain_sid, acct_flags, name.string, which_ops, machine_credentials)) { ret = false; } - + if (user_handle_out) { *user_handle_out = user_handle; } else { - printf("Testing DeleteUser (createuser test)\n"); - + torture_comment(tctx, "Testing DeleteUser (createuser test)\n"); + d.in.user_handle = &user_handle; d.out.user_handle = &user_handle; - - status = dcerpc_samr_DeleteUser(p, user_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { - printf("DeleteUser failed - %s\n", nt_errstr(status)); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, user_ctx, &d), + "DeleteUser failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + torture_warning(tctx, "DeleteUser failed - %s\n", nt_errstr(d.out.result)); ret = false; } } - + } talloc_free(user_ctx); - + return ret; } @@ -3949,7 +5403,6 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx enum torture_samr_choice which_ops, struct cli_credentials *machine_credentials) { - NTSTATUS status; struct samr_CreateUser2 r; struct samr_QueryUserInfo q; union samr_UserInfo *info; @@ -3959,6 +5412,7 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx struct lsa_String name; bool ret = true; int i; + struct dcerpc_binding_handle *b = p->binding_handle; struct { uint32_t acct_flags; @@ -3974,7 +5428,7 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx { ACB_SVRTRUST, TEST_MACHINENAME, NT_STATUS_OK }, { ACB_SVRTRUST | ACB_DISABLED, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER }, { ACB_SVRTRUST | ACB_PWNOEXP, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER }, - { ACB_DOMTRUST, TEST_DOMAINNAME, NT_STATUS_OK }, + { ACB_DOMTRUST, TEST_DOMAINNAME, NT_STATUS_ACCESS_DENIED }, { ACB_DOMTRUST | ACB_DISABLED, TEST_DOMAINNAME, NT_STATUS_INVALID_PARAMETER }, { ACB_DOMTRUST | ACB_PWNOEXP, TEST_DOMAINNAME, NT_STATUS_INVALID_PARAMETER }, { 0, TEST_ACCOUNT_NAME, NT_STATUS_INVALID_PARAMETER }, @@ -3996,47 +5450,50 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx r.out.user_handle = &user_handle; r.out.access_granted = &access_granted; r.out.rid = &rid; - - printf("Testing CreateUser2(%s, 0x%x)\n", r.in.account_name->string, acct_flags); - - status = dcerpc_samr_CreateUser2(p, user_ctx, &r); - + + torture_comment(tctx, "Testing CreateUser2(%s, 0x%x)\n", r.in.account_name->string, acct_flags); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser2_r(b, user_ctx, &r), + "CreateUser2 failed"); + if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { - printf("Server correctly refused create of '%s'\n", r.in.account_name->string); + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) { + torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.account_name->string); continue; } else { - printf("Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, - nt_errstr(status)); + torture_warning(tctx, "Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, + nt_errstr(r.out.result)); ret = false; continue; } } - if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { - if (!test_DeleteUser_byname(p, user_ctx, domain_handle, r.in.account_name->string)) { + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) { + if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.account_name->string)) { talloc_free(user_ctx); ret = false; continue; } - status = dcerpc_samr_CreateUser2(p, user_ctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser2_r(b, user_ctx, &r), + "CreateUser2 failed"); } - if (!NT_STATUS_EQUAL(status, account_types[i].nt_status)) { - printf("CreateUser2 failed gave incorrect error return - %s (should be %s)\n", - nt_errstr(status), nt_errstr(account_types[i].nt_status)); + if (!NT_STATUS_EQUAL(r.out.result, account_types[i].nt_status)) { + torture_warning(tctx, "CreateUser2 failed gave incorrect error return - %s (should be %s)\n", + nt_errstr(r.out.result), nt_errstr(account_types[i].nt_status)); ret = false; } - - if (NT_STATUS_IS_OK(status)) { + + if (NT_STATUS_IS_OK(r.out.result)) { q.in.user_handle = &user_handle; q.in.level = 5; q.out.info = &info; - - status = dcerpc_samr_QueryUserInfo(p, user_ctx, &q); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryUserInfo level %u failed - %s\n", - q.in.level, nt_errstr(status)); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, user_ctx, &q), + "QueryUserInfo failed"); + if (!NT_STATUS_IS_OK(q.out.result)) { + torture_warning(tctx, "QueryUserInfo level %u failed - %s\n", + q.in.level, nt_errstr(q.out.result)); ret = false; } else { uint32_t expected_flags = (acct_flags | ACB_PWNOTREQ | ACB_DISABLED); @@ -4044,51 +5501,54 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx expected_flags |= ACB_PW_EXPIRED; } if ((info->info5.acct_flags) != expected_flags) { - printf("QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", + torture_warning(tctx, "QueryUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n", info->info5.acct_flags, expected_flags); ret = false; - } + } switch (acct_flags) { case ACB_SVRTRUST: if (info->info5.primary_gid != DOMAIN_RID_DCS) { - printf("QuerUserInfo level 5: DC should have had Primary Group %d, got %d\n", + torture_warning(tctx, "QueryUserInfo level 5: DC should have had Primary Group %d, got %d\n", DOMAIN_RID_DCS, info->info5.primary_gid); ret = false; } break; case ACB_WSTRUST: if (info->info5.primary_gid != DOMAIN_RID_DOMAIN_MEMBERS) { - printf("QuerUserInfo level 5: Domain Member should have had Primary Group %d, got %d\n", + torture_warning(tctx, "QueryUserInfo level 5: Domain Member should have had Primary Group %d, got %d\n", DOMAIN_RID_DOMAIN_MEMBERS, info->info5.primary_gid); ret = false; } break; case ACB_NORMAL: if (info->info5.primary_gid != DOMAIN_RID_USERS) { - printf("QuerUserInfo level 5: Users should have had Primary Group %d, got %d\n", + torture_warning(tctx, "QueryUserInfo level 5: Users should have had Primary Group %d, got %d\n", DOMAIN_RID_USERS, info->info5.primary_gid); ret = false; } break; } } - - if (!test_user_ops(p, tctx, &user_handle, domain_handle, - acct_flags, name.string, which_ops, + + if (!test_user_ops(p, tctx, &user_handle, domain_handle, + domain_sid, acct_flags, name.string, which_ops, machine_credentials)) { ret = false; } - printf("Testing DeleteUser (createuser2 test)\n"); - - d.in.user_handle = &user_handle; - d.out.user_handle = &user_handle; - - status = dcerpc_samr_DeleteUser(p, user_ctx, &d); - if (!NT_STATUS_IS_OK(status)) { - printf("DeleteUser failed - %s\n", nt_errstr(status)); - ret = false; + if (!policy_handle_empty(&user_handle)) { + torture_comment(tctx, "Testing DeleteUser (createuser2 test)\n"); + + d.in.user_handle = &user_handle; + d.out.user_handle = &user_handle; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, user_ctx, &d), + "DeleteUser failed"); + if (!NT_STATUS_IS_OK(d.out.result)) { + torture_warning(tctx, "DeleteUser failed - %s\n", nt_errstr(d.out.result)); + ret = false; + } } } talloc_free(user_ctx); @@ -4097,10 +5557,10 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx return ret; } -static bool test_QueryAliasInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_QueryAliasInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryAliasInfo r; union samr_AliasInfo *info; uint16_t levels[] = {1, 2, 3}; @@ -4108,16 +5568,17 @@ static bool test_QueryAliasInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, bool ret = true; for (i=0;idescription, "test description"); } - status = dcerpc_samr_SetGroupInfo(p, mem_ctx, &s); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetGroupInfo_r(b, tctx, &s), + "SetGroupInfo failed"); if (set_ok[i]) { - if (!NT_STATUS_IS_OK(status)) { - printf("SetGroupInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetGroupInfo level %u failed - %s\n", + r.in.level, nt_errstr(s.out.result)); ret = false; continue; } } else { - if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, status)) { - printf("SetGroupInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n", - r.in.level, nt_errstr(status)); + if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, s.out.result)) { + torture_warning(tctx, "SetGroupInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n", + r.in.level, nt_errstr(s.out.result)); ret = false; continue; } @@ -4243,10 +5708,10 @@ static bool test_SetGroupInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return ret; } -static bool test_QueryUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_QueryUserInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryUserInfo r; union samr_UserInfo *info; uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, @@ -4255,16 +5720,17 @@ static bool test_QueryUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, bool ret = true; for (i=0;iinfo16.acct_flags) == 0) { - printf("Server failed to filter for 0x%x, allowed 0x%x (%d) on EnumDomainUsers\n", + torture_warning(tctx, "Server failed to filter for 0x%x, allowed 0x%x (%d) on EnumDomainUsers\n", acct_flag_mask, info->info16.acct_flags, rid); ret = false; } } - - if (!test_samr_handle_Close(p, tctx, &user_handle)) { + + if (!test_samr_handle_Close(b, tctx, &user_handle)) { ret = false; } return ret; } -static bool test_EnumDomainUsers(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle) +static bool test_EnumDomainUsers_all(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status = STATUS_MORE_ENTRIES; struct samr_EnumDomainUsers r; uint32_t mask, resume_handle=0; int i, mask_idx; @@ -4492,12 +5968,12 @@ static bool test_EnumDomainUsers(struct dcerpc_pipe *p, struct torture_context * struct samr_SamArray *sam = NULL; uint32_t num_entries = 0; - uint32_t masks[] = {ACB_NORMAL, ACB_DOMTRUST, ACB_WSTRUST, - ACB_DISABLED, ACB_NORMAL | ACB_DISABLED, - ACB_SVRTRUST | ACB_DOMTRUST | ACB_WSTRUST, + uint32_t masks[] = {ACB_NORMAL, ACB_DOMTRUST, ACB_WSTRUST, + ACB_DISABLED, ACB_NORMAL | ACB_DISABLED, + ACB_SVRTRUST | ACB_DOMTRUST | ACB_WSTRUST, ACB_PWNOEXP, 0}; - printf("Testing EnumDomainUsers\n"); + torture_comment(tctx, "Testing EnumDomainUsers\n"); for (mask_idx=0;mask_idxcount == 0) { @@ -4523,16 +6000,16 @@ static bool test_EnumDomainUsers(struct dcerpc_pipe *p, struct torture_context * for (i=0;icount;i++) { if (mask) { - if (!check_mask(p, tctx, handle, sam->entries[i].idx, mask)) { + if (!check_mask(b, tctx, handle, sam->entries[i].idx, mask)) { ret = false; } - } else if (!test_OpenUser(p, tctx, handle, sam->entries[i].idx)) { + } else if (!test_OpenUser(b, tctx, handle, sam->entries[i].idx)) { ret = false; } } } - printf("Testing LookupNames\n"); + torture_comment(tctx, "Testing LookupNames\n"); n.in.domain_handle = handle; n.in.num_names = sam->count; n.in.names = talloc_array(tctx, struct lsa_String, sam->count); @@ -4541,14 +6018,15 @@ static bool test_EnumDomainUsers(struct dcerpc_pipe *p, struct torture_context * for (i=0;icount;i++) { n.in.names[i].string = sam->entries[i].name.string; } - status = dcerpc_samr_LookupNames(p, tctx, &n); - if (!NT_STATUS_IS_OK(status)) { - printf("LookupNames failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupNames_r(b, tctx, &n), + "LookupNames failed"); + if (!NT_STATUS_IS_OK(n.out.result)) { + torture_warning(tctx, "LookupNames failed - %s\n", nt_errstr(n.out.result)); ret = false; } - printf("Testing LookupRids\n"); + torture_comment(tctx, "Testing LookupRids\n"); lr.in.domain_handle = handle; lr.in.num_rids = sam->count; lr.in.rids = talloc_array(tctx, uint32_t, sam->count); @@ -4557,24 +6035,24 @@ static bool test_EnumDomainUsers(struct dcerpc_pipe *p, struct torture_context * for (i=0;icount;i++) { lr.in.rids[i] = sam->entries[i].idx; } - status = dcerpc_samr_LookupRids(p, tctx, &lr); - torture_assert_ntstatus_ok(tctx, status, "LookupRids"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupRids_r(b, tctx, &lr), + "LookupRids failed"); + torture_assert_ntstatus_ok(tctx, lr.out.result, "LookupRids"); - return ret; + return ret; } /* try blasting the server with a bunch of sync requests */ -static bool test_EnumDomainUsers_async(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_EnumDomainUsers_async(struct dcerpc_pipe *p, struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_EnumDomainUsers r; uint32_t resume_handle=0; int i; #define ASYNC_COUNT 100 - struct rpc_request *req[ASYNC_COUNT]; + struct tevent_req *req[ASYNC_COUNT]; if (!torture_setting_bool(tctx, "dangerous", false)) { torture_skip(tctx, "samr async test disabled - enable dangerous tests to use\n"); @@ -4589,35 +6067,34 @@ static bool test_EnumDomainUsers_async(struct dcerpc_pipe *p, struct torture_con r.out.resume_handle = &resume_handle; for (i=0;iev, p->binding_handle, &r); } for (i=0;iev); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainUsers_r_recv(req[i], tctx), + talloc_asprintf(tctx, "EnumDomainUsers[%d] failed - %s\n", + i, nt_errstr(r.out.result))); } - + torture_comment(tctx, "%d async requests OK\n", i); return true; } -static bool test_EnumDomainGroups(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle) +static bool test_EnumDomainGroups_all(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_EnumDomainGroups r; uint32_t resume_handle=0; struct samr_SamArray *sam = NULL; uint32_t num_entries = 0; int i; bool ret = true; + bool universal_group_found = false; - printf("Testing EnumDomainGroups\n"); + torture_comment(tctx, "Testing EnumDomainGroups\n"); r.in.domain_handle = handle; r.in.resume_handle = &resume_handle; @@ -4626,18 +6103,33 @@ static bool test_EnumDomainGroups(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.out.num_entries = &num_entries; r.out.sam = &sam; - status = dcerpc_samr_EnumDomainGroups(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumDomainGroups failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r), + "EnumDomainGroups failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "EnumDomainGroups failed - %s\n", nt_errstr(r.out.result)); return false; } - + if (!sam) { return false; } for (i=0;icount;i++) { - if (!test_OpenGroup(p, mem_ctx, handle, sam->entries[i].idx)) { + if (!test_OpenGroup(b, tctx, handle, sam->entries[i].idx)) { + ret = false; + } + if ((ret == true) && (strcasecmp(sam->entries[i].name.string, + "Enterprise Admins") == 0)) { + universal_group_found = true; + } + } + + /* when we are running this on s4 we should get back at least the + * "Enterprise Admins" universal group. If we don't get a group entry + * at all we probably are performing the test on the builtin domain. + * So ignore this case. */ + if (torture_setting_bool(tctx, "samba4", false)) { + if ((sam->count > 0) && (!universal_group_found)) { ret = false; } } @@ -4645,10 +6137,10 @@ static bool test_EnumDomainGroups(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return ret; } -static bool test_EnumDomainAliases(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle) +static bool test_EnumDomainAliases_all(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_EnumDomainAliases r; uint32_t resume_handle=0; struct samr_SamArray *sam = NULL; @@ -4656,7 +6148,7 @@ static bool test_EnumDomainAliases(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, int i; bool ret = true; - printf("Testing EnumDomainAliases\n"); + torture_comment(tctx, "Testing EnumDomainAliases\n"); r.in.domain_handle = handle; r.in.resume_handle = &resume_handle; @@ -4665,29 +6157,30 @@ static bool test_EnumDomainAliases(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.out.num_entries = &num_entries; r.out.resume_handle = &resume_handle; - status = dcerpc_samr_EnumDomainAliases(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumDomainAliases failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r), + "EnumDomainAliases failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "EnumDomainAliases failed - %s\n", nt_errstr(r.out.result)); return false; } - + if (!sam) { return false; } for (i=0;icount;i++) { - if (!test_OpenAlias(p, mem_ctx, handle, sam->entries[i].idx)) { + if (!test_OpenAlias(b, tctx, handle, sam->entries[i].idx)) { ret = false; } } - return ret; + return ret; } -static bool test_GetDisplayEnumerationIndex(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_GetDisplayEnumerationIndex(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_GetDisplayEnumerationIndex r; bool ret = true; uint16_t levels[] = {1, 2, 3, 4, 5}; @@ -4697,7 +6190,7 @@ static bool test_GetDisplayEnumerationIndex(struct dcerpc_pipe *p, TALLOC_CTX *m int i; for (i=0;iin.domain_handle; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; for (i = 0; ; i++) { @@ -4822,28 +6319,30 @@ static bool test_each_DisplayInfo_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ct /* Not interested in validating just the account name */ return true; } - + r.out.user_handle = &user_handle; - + switch (querydisplayinfo->in.level) { case 1: case 2: - status = dcerpc_samr_OpenUser(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenUser(%u) failed - %s\n", r.in.rid, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r), + "OpenUser failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "OpenUser(%u) failed - %s\n", r.in.rid, nt_errstr(r.out.result)); return false; } } - + q.in.user_handle = &user_handle; q.in.level = 21; q.out.info = &info; - status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryUserInfo(%u) failed - %s\n", r.in.rid, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q), + "QueryUserInfo failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "QueryUserInfo(%u) failed - %s\n", r.in.rid, nt_errstr(r.out.result)); return false; } - + switch (querydisplayinfo->in.level) { case 1: if (seen_testuser && strcmp(info->info21.account_name.string, TEST_ACCOUNT_NAME) == 0) { @@ -4859,7 +6358,7 @@ static bool test_each_DisplayInfo_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ct info->info21.rid, info->info21.account_name); INT_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].acct_flags, info->info21.acct_flags, info->info21.account_name); - + break; case 2: STRING_EQUAL_QUERY(querydisplayinfo->out.info->info2.entries[i].account_name, @@ -4870,34 +6369,34 @@ static bool test_each_DisplayInfo_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ct info->info21.rid, info->info21.account_name); INT_EQUAL_QUERY((querydisplayinfo->out.info->info2.entries[i].acct_flags & ~ACB_NORMAL), info->info21.acct_flags, info->info21.account_name); - + if (!(querydisplayinfo->out.info->info2.entries[i].acct_flags & ACB_NORMAL)) { - printf("Missing ACB_NORMAL in querydisplayinfo->out.info.info2.entries[i].acct_flags on %s\n", + torture_warning(tctx, "Missing ACB_NORMAL in querydisplayinfo->out.info.info2.entries[i].acct_flags on %s\n", info->info21.account_name.string); } if (!(info->info21.acct_flags & (ACB_WSTRUST | ACB_SVRTRUST))) { - printf("Found non-trust account %s in trust account listing: 0x%x 0x%x\n", + torture_warning(tctx, "Found non-trust account %s in trust account listing: 0x%x 0x%x\n", info->info21.account_name.string, querydisplayinfo->out.info->info2.entries[i].acct_flags, info->info21.acct_flags); return false; } - + break; } - - if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) { + + if (!test_samr_handle_Close(b, tctx, &user_handle)) { return false; } } return ret; } -static bool test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_QueryDisplayInfo(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryDisplayInfo r; struct samr_QueryDomainInfo dom_info; union samr_DomainInfo *info = NULL; @@ -4911,11 +6410,11 @@ static bool test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, for (i=0;iinfo1.count; break; case 2: - if (!test_each_DisplayInfo_user(p, mem_ctx, &r, NULL)) { + if (!test_each_DisplayInfo_user(b, tctx, &r, NULL)) { ret = false; } r.in.start_idx += r.out.info->info2.count; @@ -4959,53 +6459,66 @@ static bool test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, dom_info.out.info = &info; /* Check number of users returned is correct */ - status = dcerpc_samr_QueryDomainInfo(p, mem_ctx, &dom_info); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryDomainInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); - ret = false; - break; + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &dom_info), + "QueryDomainInfo failed"); + if (!NT_STATUS_IS_OK(dom_info.out.result)) { + torture_warning(tctx, "QueryDomainInfo level %u failed - %s\n", + r.in.level, nt_errstr(dom_info.out.result)); + ret = false; + break; } switch (r.in.level) { case 1: case 4: if (info->general.num_users < r.in.start_idx) { - printf("QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n", - r.in.start_idx, info->general.num_groups, - info->general.domain_name.string); - ret = false; + /* On AD deployments this numbers don't match + * since QueryDisplayInfo returns universal and + * global groups, QueryDomainInfo only global + * ones. */ + if (torture_setting_bool(tctx, "samba3", false)) { + torture_warning(tctx, "QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n", + r.in.start_idx, info->general.num_groups, + info->general.domain_name.string); + ret = false; + } } if (!seen_testuser) { struct policy_handle user_handle; - if (NT_STATUS_IS_OK(test_OpenUser_byname(p, mem_ctx, handle, TEST_ACCOUNT_NAME, &user_handle))) { - printf("Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n", + if (NT_STATUS_IS_OK(test_OpenUser_byname(b, tctx, handle, TEST_ACCOUNT_NAME, &user_handle))) { + torture_warning(tctx, "Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n", info->general.domain_name.string); ret = false; - test_samr_handle_Close(p, mem_ctx, &user_handle); + test_samr_handle_Close(b, tctx, &user_handle); } } break; case 3: case 5: if (info->general.num_groups != r.in.start_idx) { - printf("QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n", - r.in.start_idx, info->general.num_groups, - info->general.domain_name.string); - ret = false; + /* On AD deployments this numbers don't match + * since QueryDisplayInfo returns universal and + * global groups, QueryDomainInfo only global + * ones. */ + if (torture_setting_bool(tctx, "samba3", false)) { + torture_warning(tctx, "QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n", + r.in.start_idx, info->general.num_groups, + info->general.domain_name.string); + ret = false; + } } - + break; } } - - return ret; + + return ret; } -static bool test_QueryDisplayInfo2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle) +static bool test_QueryDisplayInfo2(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryDisplayInfo2 r; bool ret = true; uint16_t levels[] = {1, 2, 3, 4, 5}; @@ -5015,7 +6528,7 @@ static bool test_QueryDisplayInfo2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, union samr_DispInfo info; for (i=0;iinfo1.entries[0].idx != r.in.start_idx + 1) { - printf("expected idx %d but got %d\n", + torture_warning(tctx, "expected idx %d but got %d\n", r.in.start_idx + 1, r.out.info->info1.entries[0].idx); break; } } - if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) && - !NT_STATUS_IS_OK(status)) { - printf("QueryDisplayInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); + if (!NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) && + !NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "QueryDisplayInfo level %u failed - %s\n", + r.in.level, nt_errstr(r.out.result)); ret = false; break; } r.in.start_idx++; - } while ((NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) || - NT_STATUS_IS_OK(status)) && + } while ((NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) || + NT_STATUS_IS_OK(r.out.result)) && *r.out.returned_size != 0); - - return ret; + + return ret; } -static bool test_QueryDomainInfo(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_QueryDomainInfo(struct dcerpc_pipe *p, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryDomainInfo r; union samr_DomainInfo *info = NULL; struct samr_SetDomainInfo s; @@ -5130,19 +6646,21 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, struct torture_context * uint16_t set_ok[] = {1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0}; int i; bool ret = true; - const char *domain_comment = talloc_asprintf(tctx, - "Tortured by Samba4 RPC-SAMR: %s", + struct dcerpc_binding_handle *b = p->binding_handle; + const char *domain_comment = talloc_asprintf(tctx, + "Tortured by Samba4 RPC-SAMR: %s", timestring(tctx, time(NULL))); s.in.domain_handle = handle; s.in.level = 4; s.in.info = talloc(tctx, union samr_DomainInfo); - + s.in.info->oem.oem_information.string = domain_comment; - status = dcerpc_samr_SetDomainInfo(p, tctx, &s); - if (!NT_STATUS_IS_OK(status)) { - printf("SetDomainInfo level %u (set comment) failed - %s\n", - r.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s), + "SetDomainInfo failed"); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetDomainInfo level %u (set comment) failed - %s\n", + s.in.level, nt_errstr(s.out.result)); return false; } @@ -5153,10 +6671,11 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, struct torture_context * r.in.level = levels[i]; r.out.info = &info; - status = dcerpc_samr_QueryDomainInfo(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryDomainInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r), + "QueryDomainInfo failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "QueryDomainInfo level %u failed - %s\n", + r.in.level, nt_errstr(r.out.result)); ret = false; continue; } @@ -5164,40 +6683,48 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, struct torture_context * switch (levels[i]) { case 2: if (strcmp(info->general.oem_information.string, domain_comment) != 0) { - printf("QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", + torture_warning(tctx, "QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", levels[i], info->general.oem_information.string, domain_comment); - ret = false; + if (!torture_setting_bool(tctx, "samba3", false)) { + ret = false; + } } if (!info->general.primary.string) { - printf("QueryDomainInfo level %u returned no PDC name\n", + torture_warning(tctx, "QueryDomainInfo level %u returned no PDC name\n", levels[i]); ret = false; } else if (info->general.role == SAMR_ROLE_DOMAIN_PDC) { if (dcerpc_server_name(p) && strcasecmp_m(dcerpc_server_name(p), info->general.primary.string) != 0) { - printf("QueryDomainInfo level %u returned different PDC name (%s) compared to server name (%s), despite claiming to be the PDC\n", - levels[i], info->general.primary.string, dcerpc_server_name(p)); + if (torture_setting_bool(tctx, "samba3", false)) { + torture_warning(tctx, "QueryDomainInfo level %u returned different PDC name (%s) compared to server name (%s), despite claiming to be the PDC\n", + levels[i], info->general.primary.string, dcerpc_server_name(p)); + } } } break; case 4: if (strcmp(info->oem.oem_information.string, domain_comment) != 0) { - printf("QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", + torture_warning(tctx, "QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n", levels[i], info->oem.oem_information.string, domain_comment); - ret = false; + if (!torture_setting_bool(tctx, "samba3", false)) { + ret = false; + } } break; case 6: if (!info->info6.primary.string) { - printf("QueryDomainInfo level %u returned no PDC name\n", + torture_warning(tctx, "QueryDomainInfo level %u returned no PDC name\n", levels[i]); ret = false; } break; case 11: if (strcmp(info->general2.general.oem_information.string, domain_comment) != 0) { - printf("QueryDomainInfo level %u returned different comment (%s, expected %s)\n", + torture_warning(tctx, "QueryDomainInfo level %u returned different comment (%s, expected %s)\n", levels[i], info->general2.general.oem_information.string, domain_comment); - ret = false; + if (!torture_setting_bool(tctx, "samba3", false)) { + ret = false; + } } break; } @@ -5208,40 +6735,42 @@ static bool test_QueryDomainInfo(struct dcerpc_pipe *p, struct torture_context * s.in.level = levels[i]; s.in.info = info; - status = dcerpc_samr_SetDomainInfo(p, tctx, &s); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s), + "SetDomainInfo failed"); if (set_ok[i]) { - if (!NT_STATUS_IS_OK(status)) { - printf("SetDomainInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); + if (!NT_STATUS_IS_OK(s.out.result)) { + torture_warning(tctx, "SetDomainInfo level %u failed - %s\n", + r.in.level, nt_errstr(s.out.result)); ret = false; continue; } } else { - if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, status)) { - printf("SetDomainInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n", - r.in.level, nt_errstr(status)); + if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, s.out.result)) { + torture_warning(tctx, "SetDomainInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n", + r.in.level, nt_errstr(s.out.result)); ret = false; continue; } } - status = dcerpc_samr_QueryDomainInfo(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("QueryDomainInfo level %u failed - %s\n", - r.in.level, nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r), + "QueryDomainInfo failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_warning(tctx, "QueryDomainInfo level %u failed - %s\n", + r.in.level, nt_errstr(r.out.result)); ret = false; continue; } } - return ret; + return ret; } -static bool test_QueryDomainInfo2(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_QueryDomainInfo2(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_QueryDomainInfo2 r; union samr_DomainInfo *info = NULL; uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13}; @@ -5249,27 +6778,30 @@ static bool test_QueryDomainInfo2(struct dcerpc_pipe *p, struct torture_context bool ret = true; for (i=0;icount; i++) { + if (rids->rids[i] == rid) { + found_member = true; + } + } + + torture_assert(tctx, found_member, "QueryGroupMember did not list newly added member"); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteGroupMember_r(b, tctx, &d), + "DeleteGroupMember failed"); + torture_assert_ntstatus_ok(tctx, d.out.result, "DeleteGroupMember"); + + rids = NULL; + found_member = false; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &q), + "QueryGroupMember failed"); + torture_assert_ntstatus_ok(tctx, q.out.result, "QueryGroupMember"); + torture_assert(tctx, rids, "QueryGroupMember did not fill in rids structure"); + + for (i=0; i < rids->count; i++) { + if (rids->rids[i] == rid) { + found_member = true; + } + } - status = dcerpc_samr_DeleteGroupMember(p, tctx, &d); - torture_assert_ntstatus_ok(tctx, status, "DeleteGroupMember"); + torture_assert(tctx, !found_member, "QueryGroupMember does still list removed member"); - status = dcerpc_samr_AddGroupMember(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "AddGroupMember"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddGroupMember_r(b, tctx, &r), + "AddGroupMember failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "AddGroupMember"); return true; } -static bool test_CreateDomainGroup(struct dcerpc_pipe *p, - struct torture_context *tctx, - struct policy_handle *domain_handle, +static bool test_CreateDomainGroup(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + const char *group_name, struct policy_handle *group_handle, - struct dom_sid *domain_sid) + struct dom_sid *domain_sid, + bool test_group) { - NTSTATUS status; struct samr_CreateDomainGroup r; uint32_t rid; struct lsa_String name; bool ret = true; - init_lsa_String(&name, TEST_GROUPNAME); + init_lsa_String(&name, group_name); r.in.domain_handle = domain_handle; r.in.name = &name; @@ -5549,89 +7141,460 @@ static bool test_CreateDomainGroup(struct dcerpc_pipe *p, r.out.group_handle = group_handle; r.out.rid = &rid; - printf("Testing CreateDomainGroup(%s)\n", r.in.name->string); + torture_comment(tctx, "Testing CreateDomainGroup(%s)\n", r.in.name->string); - status = dcerpc_samr_CreateDomainGroup(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r), + "CreateDomainGroup failed"); if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) { torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.name->string); return true; } else { - printf("Server should have refused create of '%s', got %s instead\n", r.in.name->string, - nt_errstr(status)); + torture_warning(tctx, "Server should have refused create of '%s', got %s instead\n", r.in.name->string, + nt_errstr(r.out.result)); + return false; + } + } + + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_GROUP_EXISTS)) { + if (!test_DeleteGroup_byname(b, tctx, domain_handle, r.in.name->string)) { + torture_warning(tctx, "CreateDomainGroup failed: Could not delete domain group %s - %s\n", r.in.name->string, + nt_errstr(r.out.result)); + return false; + } + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r), + "CreateDomainGroup failed"); + } + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) { + if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.name->string)) { + + torture_warning(tctx, "CreateDomainGroup failed: Could not delete user %s - %s\n", r.in.name->string, + nt_errstr(r.out.result)); + return false; + } + torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r), + "CreateDomainGroup failed"); + } + torture_assert_ntstatus_ok(tctx, r.out.result, "CreateDomainGroup"); + + if (!test_group) { + return ret; + } + + if (!test_AddGroupMember(b, tctx, domain_handle, group_handle)) { + torture_warning(tctx, "CreateDomainGroup failed - %s\n", nt_errstr(r.out.result)); + ret = false; + } + + if (!test_SetGroupInfo(b, tctx, group_handle)) { + ret = false; + } + + return ret; +} + + +/* + its not totally clear what this does. It seems to accept any sid you like. +*/ +static bool test_RemoveMemberFromForeignDomain(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle) +{ + struct samr_RemoveMemberFromForeignDomain r; + + r.in.domain_handle = domain_handle; + r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32-12-34-56-78"); + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMemberFromForeignDomain_r(b, tctx, &r), + "RemoveMemberFromForeignDomain failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMemberFromForeignDomain"); + + return true; +} + +static bool test_EnumDomainUsers(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + uint32_t *total_num_entries_p) +{ + NTSTATUS status; + struct samr_EnumDomainUsers r; + uint32_t resume_handle = 0; + uint32_t num_entries = 0; + uint32_t total_num_entries = 0; + struct samr_SamArray *sam; + + r.in.domain_handle = domain_handle; + r.in.acct_flags = 0; + r.in.max_size = (uint32_t)-1; + r.in.resume_handle = &resume_handle; + + r.out.sam = &sam; + r.out.num_entries = &num_entries; + r.out.resume_handle = &resume_handle; + + torture_comment(tctx, "Testing EnumDomainUsers\n"); + + do { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainUsers_r(b, tctx, &r), + "EnumDomainUsers failed"); + if (NT_STATUS_IS_ERR(r.out.result)) { + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to enumerate users"); + } + status = r.out.result; + + total_num_entries += num_entries; + } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)); + + if (total_num_entries_p) { + *total_num_entries_p = total_num_entries; + } + + return true; +} + +static bool test_EnumDomainGroups(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + uint32_t *total_num_entries_p) +{ + NTSTATUS status; + struct samr_EnumDomainGroups r; + uint32_t resume_handle = 0; + uint32_t num_entries = 0; + uint32_t total_num_entries = 0; + struct samr_SamArray *sam; + + r.in.domain_handle = domain_handle; + r.in.max_size = (uint32_t)-1; + r.in.resume_handle = &resume_handle; + + r.out.sam = &sam; + r.out.num_entries = &num_entries; + r.out.resume_handle = &resume_handle; + + torture_comment(tctx, "Testing EnumDomainGroups\n"); + + do { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r), + "EnumDomainGroups failed"); + if (NT_STATUS_IS_ERR(r.out.result)) { + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to enumerate groups"); + } + status = r.out.result; + + total_num_entries += num_entries; + } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)); + + if (total_num_entries_p) { + *total_num_entries_p = total_num_entries; + } + + return true; +} + +static bool test_EnumDomainAliases(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *domain_handle, + uint32_t *total_num_entries_p) +{ + NTSTATUS status; + struct samr_EnumDomainAliases r; + uint32_t resume_handle = 0; + uint32_t num_entries = 0; + uint32_t total_num_entries = 0; + struct samr_SamArray *sam; + + r.in.domain_handle = domain_handle; + r.in.max_size = (uint32_t)-1; + r.in.resume_handle = &resume_handle; + + r.out.sam = &sam; + r.out.num_entries = &num_entries; + r.out.resume_handle = &resume_handle; + + torture_comment(tctx, "Testing EnumDomainAliases\n"); + + do { + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r), + "EnumDomainAliases failed"); + if (NT_STATUS_IS_ERR(r.out.result)) { + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to enumerate aliases"); + } + status = r.out.result; + + total_num_entries += num_entries; + } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)); + + if (total_num_entries_p) { + *total_num_entries_p = total_num_entries; + } + + return true; +} + +static bool test_QueryDisplayInfo_level(struct dcerpc_binding_handle *b, + struct torture_context *tctx, + struct policy_handle *handle, + uint16_t level, + uint32_t *total_num_entries_p) +{ + NTSTATUS status; + struct samr_QueryDisplayInfo r; + uint32_t total_num_entries = 0; + + r.in.domain_handle = handle; + r.in.level = level; + r.in.start_idx = 0; + r.in.max_entries = (uint32_t)-1; + r.in.buf_size = (uint32_t)-1; + + torture_comment(tctx, "Testing QueryDisplayInfo\n"); + + do { + uint32_t total_size; + uint32_t returned_size; + union samr_DispInfo info; + + r.out.total_size = &total_size; + r.out.returned_size = &returned_size; + r.out.info = &info; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r), + "failed to query displayinfo"); + if (NT_STATUS_IS_ERR(r.out.result)) { + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to query displayinfo"); + } + status = r.out.result; + + if (*r.out.returned_size == 0) { + break; + } + + switch (r.in.level) { + case 1: + total_num_entries += info.info1.count; + r.in.start_idx += info.info1.entries[info.info1.count - 1].idx + 1; + break; + case 2: + total_num_entries += info.info2.count; + r.in.start_idx += info.info2.entries[info.info2.count - 1].idx + 1; + break; + case 3: + total_num_entries += info.info3.count; + r.in.start_idx += info.info3.entries[info.info3.count - 1].idx + 1; + break; + case 4: + total_num_entries += info.info4.count; + r.in.start_idx += info.info4.entries[info.info4.count - 1].idx + 1; + break; + case 5: + total_num_entries += info.info5.count; + r.in.start_idx += info.info5.entries[info.info5.count - 1].idx + 1; + break; + default: + return false; + } + + } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)); + + if (total_num_entries_p) { + *total_num_entries_p = total_num_entries; + } + + return true; +} + +static bool test_ManyObjects(struct dcerpc_pipe *p, + struct torture_context *tctx, + struct policy_handle *domain_handle, + struct dom_sid *domain_sid, + struct torture_samr_context *ctx) +{ + uint32_t num_total = ctx->num_objects_large_dc; + uint32_t num_enum = 0; + uint32_t num_disp = 0; + uint32_t num_created = 0; + uint32_t num_anounced = 0; + uint32_t i; + struct dcerpc_binding_handle *b = p->binding_handle; + + struct policy_handle *handles = talloc_zero_array(tctx, struct policy_handle, num_total); + + /* query */ + + { + struct samr_QueryDomainInfo2 r; + union samr_DomainInfo *info; + r.in.domain_handle = domain_handle; + r.in.level = 2; + r.out.info = &info; + + torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo2_r(b, tctx, &r), + "QueryDomainInfo2 failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "failed to query domain info"); + + switch (ctx->choice) { + case TORTURE_SAMR_MANY_ACCOUNTS: + num_anounced = info->general.num_users; + break; + case TORTURE_SAMR_MANY_GROUPS: + num_anounced = info->general.num_groups; + break; + case TORTURE_SAMR_MANY_ALIASES: + num_anounced = info->general.num_aliases; + break; + default: return false; } } - if (NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS)) { - if (!test_DeleteGroup_byname(p, tctx, domain_handle, r.in.name->string)) { - printf("CreateDomainGroup failed: Could not delete domain group %s - %s\n", r.in.name->string, - nt_errstr(status)); + /* create */ + + for (i=0; i < num_total; i++) { + + const char *name = NULL; + + switch (ctx->choice) { + case TORTURE_SAMR_MANY_ACCOUNTS: + name = talloc_asprintf(tctx, "%s%04d", TEST_ACCOUNT_NAME, i); + torture_assert(tctx, + test_CreateUser(p, tctx, domain_handle, name, &handles[i], domain_sid, 0, NULL, false), + "failed to create user"); + break; + case TORTURE_SAMR_MANY_GROUPS: + name = talloc_asprintf(tctx, "%s%04d", TEST_GROUPNAME, i); + torture_assert(tctx, + test_CreateDomainGroup(b, tctx, domain_handle, name, &handles[i], domain_sid, false), + "failed to create group"); + break; + case TORTURE_SAMR_MANY_ALIASES: + name = talloc_asprintf(tctx, "%s%04d", TEST_ALIASNAME, i); + torture_assert(tctx, + test_CreateAlias(b, tctx, domain_handle, name, &handles[i], domain_sid, false), + "failed to create alias"); + break; + default: return false; } - status = dcerpc_samr_CreateDomainGroup(p, tctx, &r); - } - if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { - if (!test_DeleteUser_byname(p, tctx, domain_handle, r.in.name->string)) { - - printf("CreateDomainGroup failed: Could not delete user %s - %s\n", r.in.name->string, - nt_errstr(status)); - return false; + if (!policy_handle_empty(&handles[i])) { + num_created++; } - status = dcerpc_samr_CreateDomainGroup(p, tctx, &r); } - torture_assert_ntstatus_ok(tctx, status, "CreateDomainGroup"); - if (!test_AddGroupMember(p, tctx, domain_handle, group_handle)) { - printf("CreateDomainGroup failed - %s\n", nt_errstr(status)); - ret = false; + /* enum */ + + switch (ctx->choice) { + case TORTURE_SAMR_MANY_ACCOUNTS: + torture_assert(tctx, + test_EnumDomainUsers(b, tctx, domain_handle, &num_enum), + "failed to enum users"); + break; + case TORTURE_SAMR_MANY_GROUPS: + torture_assert(tctx, + test_EnumDomainGroups(b, tctx, domain_handle, &num_enum), + "failed to enum groups"); + break; + case TORTURE_SAMR_MANY_ALIASES: + torture_assert(tctx, + test_EnumDomainAliases(b, tctx, domain_handle, &num_enum), + "failed to enum aliases"); + break; + default: + return false; } - if (!test_SetGroupInfo(p, tctx, group_handle)) { - ret = false; + /* dispinfo */ + + switch (ctx->choice) { + case TORTURE_SAMR_MANY_ACCOUNTS: + torture_assert(tctx, + test_QueryDisplayInfo_level(b, tctx, domain_handle, 1, &num_disp), + "failed to query display info"); + break; + case TORTURE_SAMR_MANY_GROUPS: + torture_assert(tctx, + test_QueryDisplayInfo_level(b, tctx, domain_handle, 3, &num_disp), + "failed to query display info"); + break; + case TORTURE_SAMR_MANY_ALIASES: + /* no aliases in dispinfo */ + break; + default: + return false; } - return ret; -} + /* close or delete */ + for (i=0; i < num_total; i++) { -/* - its not totally clear what this does. It seems to accept any sid you like. -*/ -static bool test_RemoveMemberFromForeignDomain(struct dcerpc_pipe *p, - struct torture_context *tctx, - struct policy_handle *domain_handle) -{ - NTSTATUS status; - struct samr_RemoveMemberFromForeignDomain r; + if (policy_handle_empty(&handles[i])) { + continue; + } - r.in.domain_handle = domain_handle; - r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32-12-34-56-78"); + if (torture_setting_bool(tctx, "samba3", false)) { + torture_assert(tctx, + test_samr_handle_Close(b, tctx, &handles[i]), + "failed to close handle"); + } else { + switch (ctx->choice) { + case TORTURE_SAMR_MANY_ACCOUNTS: + torture_assert(tctx, + test_DeleteUser(b, tctx, &handles[i]), + "failed to delete user"); + break; + case TORTURE_SAMR_MANY_GROUPS: + torture_assert(tctx, + test_DeleteDomainGroup(b, tctx, &handles[i]), + "failed to delete group"); + break; + case TORTURE_SAMR_MANY_ALIASES: + torture_assert(tctx, + test_DeleteAlias(b, tctx, &handles[i]), + "failed to delete alias"); + break; + default: + return false; + } + } + } - status = dcerpc_samr_RemoveMemberFromForeignDomain(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "RemoveMemberFromForeignDomain"); + talloc_free(handles); - return true; -} + if (ctx->choice == TORTURE_SAMR_MANY_ACCOUNTS && num_enum != num_anounced + num_created) { + torture_comment(tctx, + "unexpected number of results (%u) returned in enum call, expected %u\n", + num_enum, num_anounced + num_created); + torture_comment(tctx, + "unexpected number of results (%u) returned in dispinfo, call, expected %u\n", + num_disp, num_anounced + num_created); + } + return true; +} -static bool test_Connect(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_Connect(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle); -static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, struct dom_sid *sid, - enum torture_samr_choice which_ops, - struct cli_credentials *machine_credentials) +static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx, + struct torture_samr_context *ctx, struct dom_sid *sid) { - NTSTATUS status; struct samr_OpenDomain r; struct policy_handle domain_handle; struct policy_handle alias_handle; struct policy_handle user_handle; struct policy_handle group_handle; bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; ZERO_STRUCT(alias_handle); ZERO_STRUCT(user_handle); @@ -5640,67 +7603,92 @@ static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx, torture_comment(tctx, "Testing OpenDomain of %s\n", dom_sid_string(tctx, sid)); - r.in.connect_handle = handle; + r.in.connect_handle = &ctx->handle; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.in.sid = sid; r.out.domain_handle = &domain_handle; - status = dcerpc_samr_OpenDomain(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "OpenDomain"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &r), + "OpenDomain failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "OpenDomain failed"); /* run the domain tests with the main handle closed - this tests the servers reference counting */ - ret &= test_samr_handle_Close(p, tctx, handle); + torture_assert(tctx, test_samr_handle_Close(b, tctx, &ctx->handle), "Failed to close SAMR handle"); - switch (which_ops) { - case TORTURE_SAMR_USER_ATTRIBUTES: + switch (ctx->choice) { case TORTURE_SAMR_PASSWORDS: - ret &= test_CreateUser2(p, tctx, &domain_handle, sid, which_ops, NULL); - ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, sid, which_ops, NULL); + case TORTURE_SAMR_USER_PRIVILEGES: + if (!torture_setting_bool(tctx, "samba3", false)) { + ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, NULL); + } + ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true); + if (!ret) { + torture_warning(tctx, "Testing PASSWORDS or PRIVILEGES on domain %s failed!\n", dom_sid_string(tctx, sid)); + } + break; + case TORTURE_SAMR_USER_ATTRIBUTES: + if (!torture_setting_bool(tctx, "samba3", false)) { + ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, NULL); + } + ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true); /* This test needs 'complex' users to validate */ - ret &= test_QueryDisplayInfo(p, tctx, &domain_handle); + ret &= test_QueryDisplayInfo(b, tctx, &domain_handle); if (!ret) { - printf("Testing PASSWORDS or ATTRIBUTES on domain %s failed!\n", dom_sid_string(tctx, sid)); + torture_warning(tctx, "Testing ATTRIBUTES on domain %s failed!\n", dom_sid_string(tctx, sid)); } break; case TORTURE_SAMR_PASSWORDS_PWDLASTSET: + case TORTURE_SAMR_PASSWORDS_BADPWDCOUNT: + case TORTURE_SAMR_PASSWORDS_LOCKOUT: if (!torture_setting_bool(tctx, "samba3", false)) { - ret &= test_CreateUser2(p, tctx, &domain_handle, sid, which_ops, machine_credentials); + ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, ctx->machine_credentials); + } + ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, ctx->machine_credentials, true); + if (!ret) { + torture_warning(tctx, "Testing PASSWORDS PWDLASTSET or BADPWDCOUNT on domain %s failed!\n", dom_sid_string(tctx, sid)); } - ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, sid, which_ops, machine_credentials); + break; + case TORTURE_SAMR_MANY_ACCOUNTS: + case TORTURE_SAMR_MANY_GROUPS: + case TORTURE_SAMR_MANY_ALIASES: + ret &= test_ManyObjects(p, tctx, &domain_handle, sid, ctx); if (!ret) { - printf("Testing PASSWORDS PWDLASTSET on domain %s failed!\n", dom_sid_string(tctx, sid)); + torture_warning(tctx, "Testing MANY-{ACCOUNTS,GROUPS,ALIASES} on domain %s failed!\n", dom_sid_string(tctx, sid)); } break; case TORTURE_SAMR_OTHER: - ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, sid, which_ops, NULL); + ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true); if (!ret) { - printf("Failed to CreateUser in SAMR-OTHER on domain %s!\n", dom_sid_string(tctx, sid)); + torture_warning(tctx, "Failed to CreateUser in SAMR-OTHER on domain %s!\n", dom_sid_string(tctx, sid)); + } + if (!torture_setting_bool(tctx, "samba3", false)) { + ret &= test_QuerySecurity(b, tctx, &domain_handle); } - ret &= test_QuerySecurity(p, tctx, &domain_handle); - ret &= test_RemoveMemberFromForeignDomain(p, tctx, &domain_handle); - ret &= test_CreateAlias(p, tctx, &domain_handle, &alias_handle, sid); - ret &= test_CreateDomainGroup(p, tctx, &domain_handle, &group_handle, sid); + ret &= test_RemoveMemberFromForeignDomain(b, tctx, &domain_handle); + ret &= test_CreateAlias(b, tctx, &domain_handle, TEST_ALIASNAME, &alias_handle, sid, true); + ret &= test_CreateDomainGroup(b, tctx, &domain_handle, TEST_GROUPNAME, &group_handle, sid, true); + ret &= test_GetAliasMembership(b, tctx, &domain_handle); ret &= test_QueryDomainInfo(p, tctx, &domain_handle); - ret &= test_QueryDomainInfo2(p, tctx, &domain_handle); - ret &= test_EnumDomainUsers(p, tctx, &domain_handle); + ret &= test_QueryDomainInfo2(b, tctx, &domain_handle); + ret &= test_EnumDomainUsers_all(b, tctx, &domain_handle); ret &= test_EnumDomainUsers_async(p, tctx, &domain_handle); - ret &= test_EnumDomainGroups(p, tctx, &domain_handle); - ret &= test_EnumDomainAliases(p, tctx, &domain_handle); - ret &= test_QueryDisplayInfo2(p, tctx, &domain_handle); - ret &= test_QueryDisplayInfo3(p, tctx, &domain_handle); - ret &= test_QueryDisplayInfo_continue(p, tctx, &domain_handle); - + ret &= test_EnumDomainGroups_all(b, tctx, &domain_handle); + ret &= test_EnumDomainAliases_all(b, tctx, &domain_handle); + ret &= test_QueryDisplayInfo2(b, tctx, &domain_handle); + ret &= test_QueryDisplayInfo3(b, tctx, &domain_handle); + ret &= test_QueryDisplayInfo_continue(b, tctx, &domain_handle); + if (torture_setting_bool(tctx, "samba4", false)) { torture_comment(tctx, "skipping GetDisplayEnumerationIndex test against Samba4\n"); } else { - ret &= test_GetDisplayEnumerationIndex(p, tctx, &domain_handle); - ret &= test_GetDisplayEnumerationIndex2(p, tctx, &domain_handle); + ret &= test_GetDisplayEnumerationIndex(b, tctx, &domain_handle); + ret &= test_GetDisplayEnumerationIndex2(b, tctx, &domain_handle); } - ret &= test_GroupList(p, tctx, &domain_handle); - ret &= test_TestPrivateFunctionsDomain(p, tctx, &domain_handle); - ret &= test_RidToSid(p, tctx, sid, &domain_handle); - ret &= test_GetBootKeyInformation(p, tctx, &domain_handle); + ret &= test_GroupList(b, tctx, sid, &domain_handle); + ret &= test_TestPrivateFunctionsDomain(b, tctx, &domain_handle); + ret &= test_RidToSid(b, tctx, sid, &domain_handle); + ret &= test_GetBootKeyInformation(b, tctx, &domain_handle); if (!ret) { torture_comment(tctx, "Testing SAMR-OTHER on domain %s failed!\n", dom_sid_string(tctx, sid)); } @@ -5708,74 +7696,74 @@ static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx, } if (!policy_handle_empty(&user_handle) && - !test_DeleteUser(p, tctx, &user_handle)) { + !test_DeleteUser(b, tctx, &user_handle)) { ret = false; } if (!policy_handle_empty(&alias_handle) && - !test_DeleteAlias(p, tctx, &alias_handle)) { + !test_DeleteAlias(b, tctx, &alias_handle)) { ret = false; } if (!policy_handle_empty(&group_handle) && - !test_DeleteDomainGroup(p, tctx, &group_handle)) { + !test_DeleteDomainGroup(b, tctx, &group_handle)) { ret = false; } - ret &= test_samr_handle_Close(p, tctx, &domain_handle); + torture_assert(tctx, test_samr_handle_Close(b, tctx, &domain_handle), "Failed to close SAMR domain handle"); + torture_assert(tctx, test_Connect(b, tctx, &ctx->handle), "Faile to re-connect SAMR handle"); /* reconnect the main handle */ - ret &= test_Connect(p, tctx, handle); if (!ret) { - printf("Testing domain %s failed!\n", dom_sid_string(tctx, sid)); + torture_warning(tctx, "Testing domain %s failed!\n", dom_sid_string(tctx, sid)); } return ret; } static bool test_LookupDomain(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, const char *domain, - enum torture_samr_choice which_ops, - struct cli_credentials *machine_credentials) + struct torture_samr_context *ctx, const char *domain) { - NTSTATUS status; struct samr_LookupDomain r; struct dom_sid2 *sid = NULL; struct lsa_String n1; struct lsa_String n2; bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; torture_comment(tctx, "Testing LookupDomain(%s)\n", domain); /* check for correct error codes */ - r.in.connect_handle = handle; + r.in.connect_handle = &ctx->handle; r.in.domain_name = &n2; r.out.sid = &sid; n2.string = NULL; - status = dcerpc_samr_LookupDomain(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER, status, "LookupDomain expected NT_STATUS_INVALID_PARAMETER"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r), + "LookupDomain failed"); + torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER, r.out.result, "LookupDomain expected NT_STATUS_INVALID_PARAMETER"); init_lsa_String(&n2, "xxNODOMAINxx"); - status = dcerpc_samr_LookupDomain(p, tctx, &r); - torture_assert_ntstatus_equal(tctx, NT_STATUS_NO_SUCH_DOMAIN, status, "LookupDomain expected NT_STATUS_NO_SUCH_DOMAIN"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r), + "LookupDomain failed"); + torture_assert_ntstatus_equal(tctx, NT_STATUS_NO_SUCH_DOMAIN, r.out.result, "LookupDomain expected NT_STATUS_NO_SUCH_DOMAIN"); - r.in.connect_handle = handle; + r.in.connect_handle = &ctx->handle; init_lsa_String(&n1, domain); r.in.domain_name = &n1; - status = dcerpc_samr_LookupDomain(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "LookupDomain"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r), + "LookupDomain failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "LookupDomain"); if (!test_GetDomPwInfo(p, tctx, &n1)) { ret = false; } - if (!test_OpenDomain(p, tctx, handle, *r.out.sid, which_ops, - machine_credentials)) { + if (!test_OpenDomain(p, tctx, ctx, *r.out.sid)) { ret = false; } @@ -5784,50 +7772,50 @@ static bool test_LookupDomain(struct dcerpc_pipe *p, struct torture_context *tct static bool test_EnumDomains(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, enum torture_samr_choice which_ops, - struct cli_credentials *machine_credentials) + struct torture_samr_context *ctx) { - NTSTATUS status; struct samr_EnumDomains r; uint32_t resume_handle = 0; uint32_t num_entries = 0; struct samr_SamArray *sam = NULL; int i; bool ret = true; + struct dcerpc_binding_handle *b = p->binding_handle; - r.in.connect_handle = handle; + r.in.connect_handle = &ctx->handle; r.in.resume_handle = &resume_handle; r.in.buf_size = (uint32_t)-1; r.out.resume_handle = &resume_handle; r.out.num_entries = &num_entries; r.out.sam = &sam; - status = dcerpc_samr_EnumDomains(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "EnumDomains"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r), + "EnumDomains failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "EnumDomains failed"); if (!*r.out.sam) { return false; } for (i=0;icount;i++) { - if (!test_LookupDomain(p, tctx, handle, - sam->entries[i].name.string, which_ops, - machine_credentials)) { + if (!test_LookupDomain(p, tctx, ctx, + sam->entries[i].name.string)) { ret = false; } } - status = dcerpc_samr_EnumDomains(p, tctx, &r); - torture_assert_ntstatus_ok(tctx, status, "EnumDomains"); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r), + "EnumDomains failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, "EnumDomains failed"); return ret; } -static bool test_Connect(struct dcerpc_pipe *p, struct torture_context *tctx, +static bool test_Connect(struct dcerpc_binding_handle *b, + struct torture_context *tctx, struct policy_handle *handle) { - NTSTATUS status; struct samr_Connect r; struct samr_Connect2 r2; struct samr_Connect3 r3; @@ -5838,78 +7826,82 @@ static bool test_Connect(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t level_out = 0; bool ret = true, got_handle = false; - torture_comment(tctx, "testing samr_Connect\n"); + torture_comment(tctx, "Testing samr_Connect\n"); r.in.system_name = 0; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.connect_handle = &h; - status = dcerpc_samr_Connect(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - torture_comment(tctx, "Connect failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect_r(b, tctx, &r), + "Connect failed"); + if (!NT_STATUS_IS_OK(r.out.result)) { + torture_comment(tctx, "Connect failed - %s\n", nt_errstr(r.out.result)); ret = false; } else { got_handle = true; *handle = h; } - torture_comment(tctx, "testing samr_Connect2\n"); + torture_comment(tctx, "Testing samr_Connect2\n"); r2.in.system_name = NULL; r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r2.out.connect_handle = &h; - status = dcerpc_samr_Connect2(p, tctx, &r2); - if (!NT_STATUS_IS_OK(status)) { - torture_comment(tctx, "Connect2 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect2_r(b, tctx, &r2), + "Connect2 failed"); + if (!NT_STATUS_IS_OK(r2.out.result)) { + torture_comment(tctx, "Connect2 failed - %s\n", nt_errstr(r2.out.result)); ret = false; } else { if (got_handle) { - test_samr_handle_Close(p, tctx, handle); + test_samr_handle_Close(b, tctx, handle); } got_handle = true; *handle = h; } - torture_comment(tctx, "testing samr_Connect3\n"); + torture_comment(tctx, "Testing samr_Connect3\n"); r3.in.system_name = NULL; r3.in.unknown = 0; r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r3.out.connect_handle = &h; - status = dcerpc_samr_Connect3(p, tctx, &r3); - if (!NT_STATUS_IS_OK(status)) { - printf("Connect3 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect3_r(b, tctx, &r3), + "Connect3 failed"); + if (!NT_STATUS_IS_OK(r3.out.result)) { + torture_warning(tctx, "Connect3 failed - %s\n", nt_errstr(r3.out.result)); ret = false; } else { if (got_handle) { - test_samr_handle_Close(p, tctx, handle); + test_samr_handle_Close(b, tctx, handle); } got_handle = true; *handle = h; } - torture_comment(tctx, "testing samr_Connect4\n"); + torture_comment(tctx, "Testing samr_Connect4\n"); r4.in.system_name = ""; r4.in.client_version = 0; r4.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r4.out.connect_handle = &h; - status = dcerpc_samr_Connect4(p, tctx, &r4); - if (!NT_STATUS_IS_OK(status)) { - printf("Connect4 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect4_r(b, tctx, &r4), + "Connect4 failed"); + if (!NT_STATUS_IS_OK(r4.out.result)) { + torture_warning(tctx, "Connect4 failed - %s\n", nt_errstr(r4.out.result)); ret = false; } else { if (got_handle) { - test_samr_handle_Close(p, tctx, handle); + test_samr_handle_Close(b, tctx, handle); } got_handle = true; *handle = h; } - torture_comment(tctx, "testing samr_Connect5\n"); + torture_comment(tctx, "Testing samr_Connect5\n"); info.info1.client_version = 0; info.info1.unknown2 = 0; @@ -5922,13 +7914,14 @@ static bool test_Connect(struct dcerpc_pipe *p, struct torture_context *tctx, r5.out.info_out = &info; r5.out.connect_handle = &h; - status = dcerpc_samr_Connect5(p, tctx, &r5); - if (!NT_STATUS_IS_OK(status)) { - printf("Connect5 failed - %s\n", nt_errstr(status)); + torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect5_r(b, tctx, &r5), + "Connect5 failed"); + if (!NT_STATUS_IS_OK(r5.out.result)) { + torture_warning(tctx, "Connect5 failed - %s\n", nt_errstr(r5.out.result)); ret = false; } else { if (got_handle) { - test_samr_handle_Close(p, tctx, handle); + test_samr_handle_Close(b, tctx, handle); } got_handle = true; *handle = h; @@ -5938,29 +7931,77 @@ static bool test_Connect(struct dcerpc_pipe *p, struct torture_context *tctx, } +static bool test_samr_ValidatePassword(struct dcerpc_pipe *p, + struct torture_context *tctx) +{ + struct samr_ValidatePassword r; + union samr_ValidatePasswordReq req; + union samr_ValidatePasswordRep *repp = NULL; + NTSTATUS status; + const char *passwords[] = { "penguin", "p@ssw0rd", "p@ssw0rd123$", NULL }; + int i; + struct dcerpc_binding_handle *b = p->binding_handle; + + torture_comment(tctx, "Testing samr_ValidatePassword\n"); + + ZERO_STRUCT(r); + r.in.level = NetValidatePasswordReset; + r.in.req = &req; + r.out.rep = &repp; + + ZERO_STRUCT(req); + req.req3.account.string = "non-existant-account-aklsdji"; + + for (i=0; passwords[i]; i++) { + req.req3.password.string = passwords[i]; + + status = dcerpc_samr_ValidatePassword_r(b, tctx, &r); + if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { + torture_skip(tctx, "ValidatePassword not supported by server\n"); + } + torture_assert_ntstatus_ok(tctx, status, + "samr_ValidatePassword failed"); + torture_assert_ntstatus_ok(tctx, r.out.result, + "samr_ValidatePassword failed"); + torture_comment(tctx, "Server %s password '%s' with code %i\n", + repp->ctr3.status==SAMR_VALIDATION_STATUS_SUCCESS?"allowed":"refused", + req.req3.password.string, repp->ctr3.status); + } + + return true; +} + bool torture_rpc_samr(struct torture_context *torture) { NTSTATUS status; struct dcerpc_pipe *p; bool ret = true; - struct policy_handle handle; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; status = torture_rpc_connection(torture, &p, &ndr_table_samr); if (!NT_STATUS_IS_OK(status)) { return false; } + b = p->binding_handle; - ret &= test_Connect(p, torture, &handle); + ctx = talloc_zero(torture, struct torture_samr_context); - ret &= test_QuerySecurity(p, torture, &handle); + ctx->choice = TORTURE_SAMR_OTHER; - ret &= test_EnumDomains(p, torture, &handle, TORTURE_SAMR_OTHER, NULL); + ret &= test_Connect(b, torture, &ctx->handle); - ret &= test_SetDsrmPassword(p, torture, &handle); + if (!torture_setting_bool(torture, "samba3", false)) { + ret &= test_QuerySecurity(b, torture, &ctx->handle); + } + + ret &= test_EnumDomains(p, torture, ctx); - ret &= test_Shutdown(p, torture, &handle); + ret &= test_SetDsrmPassword(b, torture, &ctx->handle); - ret &= test_samr_handle_Close(p, torture, &handle); + ret &= test_Shutdown(b, torture, &ctx->handle); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); return ret; } @@ -5971,24 +8012,32 @@ bool torture_rpc_samr_users(struct torture_context *torture) NTSTATUS status; struct dcerpc_pipe *p; bool ret = true; - struct policy_handle handle; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; status = torture_rpc_connection(torture, &p, &ndr_table_samr); if (!NT_STATUS_IS_OK(status)) { return false; } + b = p->binding_handle; - ret &= test_Connect(p, torture, &handle); + ctx = talloc_zero(torture, struct torture_samr_context); - ret &= test_QuerySecurity(p, torture, &handle); + ctx->choice = TORTURE_SAMR_USER_ATTRIBUTES; - ret &= test_EnumDomains(p, torture, &handle, TORTURE_SAMR_USER_ATTRIBUTES, NULL); + ret &= test_Connect(b, torture, &ctx->handle); - ret &= test_SetDsrmPassword(p, torture, &handle); + if (!torture_setting_bool(torture, "samba3", false)) { + ret &= test_QuerySecurity(b, torture, &ctx->handle); + } + + ret &= test_EnumDomains(p, torture, ctx); - ret &= test_Shutdown(p, torture, &handle); + ret &= test_SetDsrmPassword(b, torture, &ctx->handle); - ret &= test_samr_handle_Close(p, torture, &handle); + ret &= test_Shutdown(b, torture, &ctx->handle); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); return ret; } @@ -5999,18 +8048,26 @@ bool torture_rpc_samr_passwords(struct torture_context *torture) NTSTATUS status; struct dcerpc_pipe *p; bool ret = true; - struct policy_handle handle; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; status = torture_rpc_connection(torture, &p, &ndr_table_samr); if (!NT_STATUS_IS_OK(status)) { return false; } + b = p->binding_handle; - ret &= test_Connect(p, torture, &handle); + ctx = talloc_zero(torture, struct torture_samr_context); - ret &= test_EnumDomains(p, torture, &handle, TORTURE_SAMR_PASSWORDS, NULL); + ctx->choice = TORTURE_SAMR_PASSWORDS; - ret &= test_samr_handle_Close(p, torture, &handle); + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + ret &= test_samr_ValidatePassword(p, torture); return ret; } @@ -6022,30 +8079,35 @@ static bool torture_rpc_samr_pwdlastset(struct torture_context *torture, NTSTATUS status; struct dcerpc_pipe *p; bool ret = true; - struct policy_handle handle; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; status = torture_rpc_connection(torture, &p, &ndr_table_samr); if (!NT_STATUS_IS_OK(status)) { return false; } + b = p->binding_handle; - ret &= test_Connect(p, torture, &handle); + ctx = talloc_zero(torture, struct torture_samr_context); - ret &= test_EnumDomains(p, torture, &handle, - TORTURE_SAMR_PASSWORDS_PWDLASTSET, - machine_credentials); + ctx->choice = TORTURE_SAMR_PASSWORDS_PWDLASTSET; + ctx->machine_credentials = machine_credentials; - ret &= test_samr_handle_Close(p, torture, &handle); + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); return ret; } struct torture_suite *torture_rpc_samr_passwords_pwdlastset(TALLOC_CTX *mem_ctx) { - struct torture_suite *suite = torture_suite_create(mem_ctx, "SAMR-PASSWORDS-PWDLASTSET"); + struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.pwdlastset"); struct torture_rpc_tcase *tcase; - tcase = torture_suite_add_machine_rpc_iface_tcase(suite, "samr", + tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr", &ndr_table_samr, TEST_ACCOUNT_NAME_PWD); @@ -6054,3 +8116,251 @@ struct torture_suite *torture_rpc_samr_passwords_pwdlastset(TALLOC_CTX *mem_ctx) return suite; } + +static bool torture_rpc_samr_users_privileges_delete_user(struct torture_context *torture, + struct dcerpc_pipe *p2, + struct cli_credentials *machine_credentials) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx = talloc_zero(torture, struct torture_samr_context); + + ctx->choice = TORTURE_SAMR_USER_PRIVILEGES; + ctx->machine_credentials = machine_credentials; + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +struct torture_suite *torture_rpc_samr_user_privileges(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.users.privileges"); + struct torture_rpc_tcase *tcase; + + tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr", + &ndr_table_samr, + TEST_ACCOUNT_NAME_PWD); + + torture_rpc_tcase_add_test_creds(tcase, "delete_privileged_user", + torture_rpc_samr_users_privileges_delete_user); + + return suite; +} + +static bool torture_rpc_samr_many_accounts(struct torture_context *torture, + struct dcerpc_pipe *p2, + void *data) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx = + talloc_get_type_abort(data, struct torture_samr_context); + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx->choice = TORTURE_SAMR_MANY_ACCOUNTS; + ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc", + ctx->num_objects_large_dc); + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +static bool torture_rpc_samr_many_groups(struct torture_context *torture, + struct dcerpc_pipe *p2, + void *data) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx = + talloc_get_type_abort(data, struct torture_samr_context); + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx->choice = TORTURE_SAMR_MANY_GROUPS; + ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc", + ctx->num_objects_large_dc); + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +static bool torture_rpc_samr_many_aliases(struct torture_context *torture, + struct dcerpc_pipe *p2, + void *data) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx = + talloc_get_type_abort(data, struct torture_samr_context); + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx->choice = TORTURE_SAMR_MANY_ALIASES; + ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc", + ctx->num_objects_large_dc); + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +struct torture_suite *torture_rpc_samr_large_dc(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.large-dc"); + struct torture_rpc_tcase *tcase; + struct torture_samr_context *ctx; + + tcase = torture_suite_add_rpc_iface_tcase(suite, "samr", &ndr_table_samr); + + ctx = talloc_zero(suite, struct torture_samr_context); + ctx->num_objects_large_dc = 150; + + torture_rpc_tcase_add_test_ex(tcase, "many_aliases", + torture_rpc_samr_many_aliases, ctx); + torture_rpc_tcase_add_test_ex(tcase, "many_groups", + torture_rpc_samr_many_groups, ctx); + torture_rpc_tcase_add_test_ex(tcase, "many_accounts", + torture_rpc_samr_many_accounts, ctx); + + return suite; +} + +static bool torture_rpc_samr_badpwdcount(struct torture_context *torture, + struct dcerpc_pipe *p2, + struct cli_credentials *machine_credentials) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx = talloc_zero(torture, struct torture_samr_context); + + ctx->choice = TORTURE_SAMR_PASSWORDS_BADPWDCOUNT; + ctx->machine_credentials = machine_credentials; + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +struct torture_suite *torture_rpc_samr_passwords_badpwdcount(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.badpwdcount"); + struct torture_rpc_tcase *tcase; + + tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr", + &ndr_table_samr, + TEST_ACCOUNT_NAME_PWD); + + torture_rpc_tcase_add_test_creds(tcase, "badPwdCount", + torture_rpc_samr_badpwdcount); + + return suite; +} + +static bool torture_rpc_samr_lockout(struct torture_context *torture, + struct dcerpc_pipe *p2, + struct cli_credentials *machine_credentials) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + bool ret = true; + struct torture_samr_context *ctx; + struct dcerpc_binding_handle *b; + + status = torture_rpc_connection(torture, &p, &ndr_table_samr); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + b = p->binding_handle; + + ctx = talloc_zero(torture, struct torture_samr_context); + + ctx->choice = TORTURE_SAMR_PASSWORDS_LOCKOUT; + ctx->machine_credentials = machine_credentials; + + ret &= test_Connect(b, torture, &ctx->handle); + + ret &= test_EnumDomains(p, torture, ctx); + + ret &= test_samr_handle_Close(b, torture, &ctx->handle); + + return ret; +} + +struct torture_suite *torture_rpc_samr_passwords_lockout(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.lockout"); + struct torture_rpc_tcase *tcase; + + tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr", + &ndr_table_samr, + TEST_ACCOUNT_NAME_PWD); + + torture_rpc_tcase_add_test_creds(tcase, "lockout", + torture_rpc_samr_lockout); + + return suite; +} + +