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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "system/time.h"
#include "librpc/gen_ndr/lsa.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
-#include "smb.h"
#include "lib/crypto/crypto.h"
#include "libcli/auth/libcli_auth.h"
#include "libcli/security/security.h"
s.in.sec_info = 7;
s.in.sdbuf = r.out.sdbuf;
- if (lp_parm_bool(-1, "target", "samba4", False)) {
+ if (lp_parm_bool(-1, "torture", "samba4", False)) {
printf("skipping SetSecurity test against Samba4\n");
return True;
}
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);
+ TEST_USERINFO_STRING(6, full_name, 3, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 5, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 6, full_name, "", 0);
+ 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, "",
+ 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, 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);
+ TEST_USERINFO_STRING(10, home_directory, 5, home_directory, "xx10-5 home_directory", 0);
+ TEST_USERINFO_STRING(10, home_directory, 21, home_directory, "xx10-21 home_directory", 0);
+ TEST_USERINFO_STRING(21, home_directory, 21, home_directory, "xx21-21 home_directory",
+ SAMR_FIELD_HOME_DIRECTORY);
+ TEST_USERINFO_STRING(21, home_directory, 10, home_directory, "xx21-10 home_directory",
+ SAMR_FIELD_HOME_DIRECTORY);
+
+ TEST_USERINFO_STRING(10, home_drive, 3, home_drive, "xx10-3 home_drive", 0);
+ TEST_USERINFO_STRING(10, home_drive, 5, home_drive, "xx10-5 home_drive", 0);
+ TEST_USERINFO_STRING(10, home_drive, 21, home_drive, "xx10-21 home_drive", 0);
+ TEST_USERINFO_STRING(21, home_drive, 21, home_drive, "xx21-21 home_drive",
+ 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_INT(21, code_page, 21, 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(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,
SAMR_FIELD_LOGON_HOURS);
- if (lp_parm_bool(-1, "target", "samba4", False)) {
+ if (lp_parm_bool(-1, "torture", "samba4", False)) {
printf("skipping Set Account Flag tests against Samba4\n");
return ret;
}
return s;
}
+/*
+ generate a random password for password change tests (fixed length)
+*/
+static char *samr_rand_pass_fixed_len(TALLOC_CTX *mem_ctx, int len)
+{
+ char *s = generate_random_str(mem_ctx, len);
+ printf("Generated password '%s'\n", s);
+ return s;
+}
+
static BOOL test_SetUserPass(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *handle, char **password)
{
*password = newpass;
}
+ encode_pw_buffer(u.info23.password.data, newpass, STR_UNICODE);
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return False;
+ }
+
+ /* This should break the key nicely */
+ session_key.length--;
+ arcfour_crypt_blob(u.info23.password.data, 516, &session_key);
+
+ printf("Testing SetUserInfo level 23 (set password) with wrong password\n");
+
+ status = dcerpc_samr_SetUserInfo(p, mem_ctx, &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));
+ ret = False;
+ }
+
return ret;
}
static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle, char **password)
+ struct policy_handle *handle, bool makeshort,
+ char **password)
{
NTSTATUS status;
struct samr_SetUserInfo s;
if (NT_STATUS_IS_OK(status)) {
policy_min_pw_len = pwp.out.info.min_password_length;
}
- newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+ if (makeshort && policy_min_pw_len) {
+ newpass = samr_rand_pass_fixed_len(mem_ctx, policy_min_pw_len - 1);
+ } else {
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+ }
s.in.user_handle = handle;
s.in.info = &u;
*password = newpass;
}
+ /* This should break the key nicely */
+ confounded_session_key.data[0]++;
+
+ arcfour_crypt_blob(u.info26.password.data, 516, &confounded_session_key);
+ memcpy(&u.info26.password.data[516], confounder, 16);
+
+ printf("Testing SetUserInfo level 26 (set password ex) with wrong session key\n");
+
+ status = dcerpc_samr_SetUserInfo(p, mem_ctx, &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));
+ ret = False;
+ } else {
+ *password = newpass;
+ }
+
return ret;
}
*password = newpass;
}
+ /* This should break the key nicely */
+ confounded_session_key.data[0]++;
+
+ arcfour_crypt_blob(u.info25.password.data, 516, &confounded_session_key);
+ memcpy(&u.info25.password.data[516], confounder, 16);
+
+ printf("Testing SetUserInfo level 25 (set password ex) with wrong session key\n");
+
+ status = dcerpc_samr_SetUserInfo(p, mem_ctx, &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));
+ ret = False;
+ }
+
return ret;
}
status = dcerpc_samr_LookupNames(p, mem_ctx, &n);
if (!NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
printf("LookupNames[2] failed - %s\n", nt_errstr(status));
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
return status;
}
- init_lsa_String(&sname[1], "xxNONAMExx");
n.in.num_names = 0;
status = dcerpc_samr_LookupNames(p, mem_ctx, &n);
if (!NT_STATUS_IS_OK(status)) {
printf("LookupNames[0] failed - %s\n", nt_errstr(status));
+ return status;
}
- return status;
+ init_lsa_String(&sname[0], "xxNONAMExx");
+ n.in.num_names = 1;
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &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)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return status;
+ }
+
+ init_lsa_String(&sname[0], "xxNONAMExx");
+ init_lsa_String(&sname[1], "xxNONAME2xx");
+ n.in.num_names = 2;
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &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)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return status;
+ }
+
+ return NT_STATUS_OK;
}
static NTSTATUS test_OpenUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.out.user_handle = user_handle;
status = dcerpc_samr_OpenUser(p, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
- printf("OpenUser_byname(%s) failed - %s\n", name, nt_errstr(status));
+ printf("OpenUser_byname(%s -> %d) failed - %s\n", name, rid, nt_errstr(status));
}
return status;
char *oldpass;
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
+ BOOL changed = True;
char *newpass;
struct samr_GetUserPwInfo pwp;
E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ /* Break the LM hash */
+ hash1.hash[0]++;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+ printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM hash, got %s\n", nt_errstr(status));
+ ret = False;
+ }
+
+ /* Unbreak the LM hash */
+ hash1.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ /* Break the NT hash */
+ hash3.hash[0]--;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+ printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT hash, got %s\n", nt_errstr(status));
+ ret = False;
+ }
+
+ /* Unbreak the NT hash */
+ hash3.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ /* Break the LM cross */
+ hash6.hash[0]++;
+ r.in.lm_cross = &hash6;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &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));
+ ret = False;
+ }
+
+ /* Unbreak the LM cross */
+ hash6.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ /* Break the NT cross */
+ hash5.hash[0]++;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &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));
+ ret = False;
+ }
+
+ /* Unbreak the NT cross */
+ hash5.hash[0]--;
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 0;
+ r.in.lm_cross = NULL;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r);
+ if (NT_STATUS_IS_OK(status)) {
+ 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));
+ ret = False;
+ }
+
+ oldpass = newpass;
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 0;
+ r.in.nt_cross = NULL;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r);
+ if (NT_STATUS_IS_OK(status)) {
+ 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));
+ ret = False;
+ }
+
+ oldpass = newpass;
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
r.in.user_handle = &user_handle;
r.in.lm_present = 1;
r.in.old_lm_crypted = &hash1;
printf("ChangePasswordUser failed - %s\n", nt_errstr(status));
ret = False;
} else {
+ changed = True;
*password = newpass;
}
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ if (changed) {
+ status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &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));
+ ret = False;
+ }
+ }
+
+
if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) {
ret = False;
}
ret = False;
}
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+ /* Break the old password */
+ old_lm_hash[0]++;
+ arcfour_crypt(lm_pass.data, old_lm_hash, 516);
+ /* unbreak it for the next operation */
+ old_lm_hash[0]--;
+ E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
+
+ status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &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));
+ ret = False;
+ }
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+ arcfour_crypt(lm_pass.data, old_lm_hash, 516);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = NULL;
+
+ status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER (or at least 'PASSWORD_RESTRICTON') for no supplied validation hash - %s\n",
+ nt_errstr(status));
+ ret = False;
+ }
+
+ /* This shouldn't be a valid name */
+ account_bad.string = TEST_ACCOUNT_NAME "XX";
+ r.in.account = &account_bad;
+
+ status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER for no supplied validation hash and invalid user - %s\n",
+ nt_errstr(status));
+ ret = False;
+ }
+
/* This shouldn't be a valid name */
account_bad.string = TEST_ACCOUNT_NAME "XX";
r.in.account = &account_bad;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r);
ret = False;
}
+ /* This shouldn't be a valid name */
+ account_bad.string = TEST_ACCOUNT_NAME "XX";
+ r.in.account = &account_bad;
+ r.in.password = NULL;
+ r.in.hash = &lm_verifier;
+
+ status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER for no supplied password and invalid user - %s\n",
+ nt_errstr(status));
+ ret = False;
+ }
+
E_deshash(oldpass, old_lm_hash);
E_deshash(newpass, new_lm_hash);
static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
const char *acct_name,
- struct policy_handle *handle, char **password)
+ char **password,
+ char *newpass, bool allow_password_restriction)
{
NTSTATUS status;
struct samr_ChangePasswordUser2 r;
struct samr_CryptPassword nt_pass, lm_pass;
struct samr_Password nt_verifier, lm_verifier;
char *oldpass;
- char *newpass;
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
struct samr_GetDomPwInfo dom_pw_info;
- int policy_min_pw_len = 0;
struct lsa_String domain_name;
-
domain_name.string = "";
dom_pw_info.in.domain_name = &domain_name;
- printf("Testing ChangePasswordUser2\n");
+ printf("Testing ChangePasswordUser2 on %s\n", acct_name);
if (!*password) {
printf("Failing ChangePasswordUser3 as old password was NULL. Previous test failed?\n");
}
oldpass = *password;
- status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &dom_pw_info);
- if (NT_STATUS_IS_OK(status)) {
- policy_min_pw_len = dom_pw_info.out.info.min_password_length;
- }
+ if (!newpass) {
+ int policy_min_pw_len = 0;
+ status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &dom_pw_info);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = dom_pw_info.out.info.min_password_length;
+ }
- newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+ }
server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
init_lsa_String(&account, acct_name);
r.in.lm_verifier = &lm_verifier;
status = dcerpc_samr_ChangePasswordUser2(p, mem_ctx, &r);
- if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
+ 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));
BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
const char *account_string,
int policy_min_pw_len,
- char **password)
+ char **password,
+ const char *newpass,
+ NTTIME last_password_change,
+ BOOL handle_reject_reason)
{
NTSTATUS status;
struct samr_ChangePasswordUser3 r;
struct samr_CryptPassword nt_pass, lm_pass;
struct samr_Password nt_verifier, lm_verifier;
char *oldpass;
- char *newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
+ NTTIME t;
printf("Testing ChangePasswordUser3\n");
+ if (newpass == NULL) {
+ do {
+ if (policy_min_pw_len == 0) {
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+ } else {
+ newpass = samr_rand_pass_fixed_len(mem_ctx, policy_min_pw_len);
+ }
+ } while (check_password_quality(newpass) == False);
+ } else {
+ printf("Using password '%s'\n", newpass);
+ }
+
if (!*password) {
printf("Failing ChangePasswordUser3 as old password was NULL. Previous test failed?\n");
return False;
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);
+
+ encode_pw_buffer(nt_pass.data, newpass, STR_UNICODE);
+ /* Break the NT hash */
+ old_nt_hash[0]++;
+ arcfour_crypt(nt_pass.data, old_nt_hash, 516);
+ /* 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;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+ r.in.password3 = NULL;
+
+ status = dcerpc_samr_ChangePasswordUser3(p, mem_ctx, &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));
+ ret = False;
+ }
+
/* This shouldn't be a valid name */
init_lsa_String(&account_bad, talloc_asprintf(mem_ctx, "%sXX", account_string));
r.in.lm_verifier = &lm_verifier;
r.in.password3 = NULL;
+ unix_to_nt_time(&t, time(NULL));
+
status = dcerpc_samr_ChangePasswordUser3(p, mem_ctx, &r);
- if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)
- && !policy_min_pw_len) {
- if (r.out.dominfo) {
- policy_min_pw_len = r.out.dominfo->min_password_length;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)
+ && r.out.dominfo
+ && r.out.reject
+ && handle_reject_reason
+ && (!null_nttime(last_password_change) || !r.out.dominfo->min_password_age)) {
+ if (r.out.dominfo->password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE ) {
+
+ if (r.out.reject && (r.out.reject->reason != SAMR_REJECT_OTHER)) {
+ printf("expected SAMR_REJECT_OTHER (%d), got %d\n",
+ SAMR_REJECT_OTHER, r.out.reject->reason);
+ return False;
+ }
}
- if (policy_min_pw_len) /* try again with the right min password length */ {
- ret = test_ChangePasswordUser3(p, mem_ctx, account_string, policy_min_pw_len, password);
- } else {
- printf("ChangePasswordUser3 failed (no min length known) - %s\n", nt_errstr(status));
- ret = False;
+
+ /* We tested the order of precendence which is as follows:
+
+ * pwd min_age
+ * pwd length
+ * pwd complexity
+ * pwd history
+
+ Guenther */
+
+ if ((r.out.dominfo->min_password_age > 0) && !null_nttime(last_password_change) &&
+ (last_password_change + r.out.dominfo->min_password_age > t)) {
+
+ if (r.out.reject->reason != SAMR_REJECT_OTHER) {
+ printf("expected SAMR_REJECT_OTHER (%d), got %d\n",
+ SAMR_REJECT_OTHER, r.out.reject->reason);
+ return False;
+ }
+
+ } else if ((r.out.dominfo->min_password_length > 0) &&
+ (strlen(newpass) < r.out.dominfo->min_password_length)) {
+
+ if (r.out.reject->reason != SAMR_REJECT_TOO_SHORT) {
+ printf("expected SAMR_REJECT_TOO_SHORT (%d), got %d\n",
+ SAMR_REJECT_TOO_SHORT, r.out.reject->reason);
+ return False;
+ }
+
+ } else if ((r.out.dominfo->password_history_length > 0) &&
+ strequal(oldpass, newpass)) {
+
+ if (r.out.reject->reason != SAMR_REJECT_IN_HISTORY) {
+ printf("expected SAMR_REJECT_IN_HISTORY (%d), got %d\n",
+ SAMR_REJECT_IN_HISTORY, r.out.reject->reason);
+ return False;
+ }
+ } else if (r.out.dominfo->password_properties & DOMAIN_PASSWORD_COMPLEX) {
+
+ if (r.out.reject->reason != SAMR_REJECT_COMPLEXITY) {
+ printf("expected SAMR_REJECT_COMPLEXITY (%d), got %d\n",
+ SAMR_REJECT_COMPLEXITY, r.out.reject->reason);
+ return False;
+ }
+
}
+
+ if (r.out.reject->reason == SAMR_REJECT_TOO_SHORT) {
+ /* retry with adjusted size */
+ return test_ChangePasswordUser3(p, mem_ctx, account_string,
+ r.out.dominfo->min_password_length,
+ password, NULL, 0, False);
+
+ }
+
} else if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
- printf("ChangePasswordUser3 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status));
+ if (r.out.reject && r.out.reject->reason != SAMR_REJECT_OTHER) {
+ printf("expected SAMR_REJECT_OTHER (%d), got %d\n",
+ SAMR_REJECT_OTHER, r.out.reject->reason);
+ 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));
ret = False;
} else {
- *password = newpass;
+ *password = talloc_strdup(mem_ctx, newpass);
}
return ret;
}
break;
case TORTURE_SAMR_PASSWORDS:
+ if (base_acct_flags & (ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) {
+ char simple_pass[9];
+ char *v = generate_random_str(mem_ctx, 1);
+
+ ZERO_STRUCT(simple_pass);
+ memset(simple_pass, *v, sizeof(simple_pass) - 1);
+
+ printf("Testing machine account password policy rules\n");
+
+ /* Workstation trust accounts don't seem to need to honour password quality policy */
+ if (!test_SetUserPassEx(p, user_ctx, user_handle, true, &password)) {
+ ret = False;
+ }
+
+ if (!test_ChangePasswordUser2(p, user_ctx, base_acct_name, &password, simple_pass, False)) {
+ ret = False;
+ }
+
+ /* reset again, to allow another 'user' password change */
+ if (!test_SetUserPassEx(p, user_ctx, user_handle, true, &password)) {
+ ret = False;
+ }
+
+ /* Try a 'short' password */
+ if (!test_ChangePasswordUser2(p, user_ctx, base_acct_name, &password, samr_rand_pass(mem_ctx, 4), False)) {
+ ret = False;
+ }
+
+ }
+
for (i = 0; password_fields[i]; i++) {
if (!test_SetUserPass_23(p, user_ctx, user_handle, password_fields[i], &password)) {
ret = False;
}
/* check it was set right */
- if (!test_ChangePasswordUser3(p, user_ctx, base_acct_name, 0, &password)) {
+ if (!test_ChangePasswordUser3(p, user_ctx, base_acct_name, 0, &password, NULL, 0, False)) {
ret = False;
}
}
}
/* check it was set right */
- if (!test_ChangePasswordUser3(p, user_ctx, base_acct_name, 0, &password)) {
+ if (!test_ChangePasswordUser3(p, user_ctx, base_acct_name, 0, &password, NULL, 0, False)) {
ret = False;
}
}
- if (!test_SetUserPassEx(p, user_ctx, user_handle, &password)) {
+ if (!test_SetUserPassEx(p, user_ctx, user_handle, false, &password)) {
ret = False;
}
if (!test_ChangePassword(p, user_ctx, base_acct_name, domain_handle, &password)) {
ret = False;
}
+
break;
case TORTURE_SAMR_OTHER:
- /* Can't happen */
+ /* We just need the account to exist */
break;
}
talloc_free(user_ctx);
ret = False;
}
- if (lp_parm_bool(-1, "target", "samba4", False)) {
+ if (lp_parm_bool(-1, "torture", "samba4", False)) {
printf("skipping MultipleMembers Alias tests against Samba4\n");
return ret;
}
}
+static BOOL test_DeleteUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle)
+{
+ struct samr_DeleteUser d;
+ NTSTATUS status;
+ BOOL ret = True;
+ printf("Testing DeleteUser\n");
+
+ 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)) {
+ printf("DeleteUser failed - %s\n", nt_errstr(status));
+ ret = False;
+ }
+
+ return ret;
+}
+
BOOL test_DeleteUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *handle, const char *name)
{
r.out.alias_handle = alias_handle;
r.out.rid = &rid;
- printf("Testing CreateAlias (%s)\n", r.in.alias_name->string);
+ printf("Testing CreateAlias (%s)\n", r.in.alias_name->string);
+
+ status = dcerpc_samr_CreateDomAlias(p, mem_ctx, &r);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ printf("Server refused create of '%s'\n", r.in.alias_name->string);
+ return True;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ALIAS_EXISTS)) {
+ if (!test_DeleteAlias_byname(p, mem_ctx, domain_handle, r.in.alias_name->string)) {
+ return False;
+ }
+ status = dcerpc_samr_CreateDomAlias(p, mem_ctx, &r);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateAlias failed - %s\n", nt_errstr(status));
+ return False;
+ }
+
+ if (!test_alias_ops(p, mem_ctx, alias_handle, domain_sid)) {
+ ret = False;
+ }
+
+ return ret;
+}
+
+static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ const char *acct_name,
+ struct policy_handle *domain_handle, char **password)
+{
+ BOOL ret = True;
+
+ if (!*password) {
+ return False;
+ }
+
+ if (!test_ChangePasswordUser(p, mem_ctx, acct_name, domain_handle, password)) {
+ ret = False;
+ }
+
+ if (!test_ChangePasswordUser2(p, mem_ctx, acct_name, password, 0, True)) {
+ ret = False;
+ }
+
+ if (!test_OemChangePasswordUser2(p, mem_ctx, 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)) {
+ ret = False;
+ }
+
+ {
+ char simple_pass[9];
+ char *v = generate_random_str(mem_ctx, 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)) {
+ ret = False;
+ }
+ }
+
+ /* set samr_SetDomainInfo level 1 with min_length 5 */
+ {
+ struct samr_QueryDomainInfo r;
+ struct samr_SetDomainInfo s;
+ uint16_t len_old, len;
+ uint32_t pwd_prop_old;
+ int64_t min_pwd_age_old;
+ NTSTATUS status;
+
+ len = 5;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = 1;
+
+ printf("testing samr_QueryDomainInfo level 1\n");
+ status = dcerpc_samr_QueryDomainInfo(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ s.in.domain_handle = domain_handle;
+ s.in.level = 1;
+ s.in.info = r.out.info;
- status = dcerpc_samr_CreateDomAlias(p, mem_ctx, &r);
+ /* remember the old min length, so we can reset it */
+ len_old = s.in.info->info1.min_password_length;
+ s.in.info->info1.min_password_length = len;
+ pwd_prop_old = s.in.info->info1.password_properties;
+ /* turn off password complexity checks for this test */
+ s.in.info->info1.password_properties &= ~DOMAIN_PASSWORD_COMPLEX;
- if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
- printf("Server refused create of '%s'\n", r.in.alias_name->string);
- return True;
- }
+ min_pwd_age_old = s.in.info->info1.min_password_age;
+ s.in.info->info1.min_password_age = 0;
- if (NT_STATUS_EQUAL(status, NT_STATUS_ALIAS_EXISTS)) {
- if (!test_DeleteAlias_byname(p, mem_ctx, domain_handle, r.in.alias_name->string)) {
+ printf("testing samr_SetDomainInfo level 1\n");
+ status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s);
+ if (!NT_STATUS_IS_OK(status)) {
return False;
}
- status = dcerpc_samr_CreateDomAlias(p, mem_ctx, &r);
- }
- if (!NT_STATUS_IS_OK(status)) {
- printf("CreateAlias failed - %s\n", nt_errstr(status));
- return False;
- }
+ printf("calling test_ChangePasswordUser3 with too short password\n");
+
+ if (!test_ChangePasswordUser3(p, mem_ctx, 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)) {
+ return False;
+ }
- if (!test_alias_ops(p, mem_ctx, alias_handle, domain_sid)) {
- ret = False;
}
- return ret;
-}
+ {
+ NTSTATUS status;
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ struct samr_LookupNames n;
+ struct policy_handle user_handle;
-static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- const char *acct_name,
- struct policy_handle *domain_handle, char **password)
-{
- BOOL ret = True;
+ 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;
- if (!*password) {
- return False;
- }
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupNames failed - %s\n", nt_errstr(status));
+ return False;
+ }
- if (!test_ChangePasswordUser(p, mem_ctx, acct_name, domain_handle, password)) {
- ret = False;
- }
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = n.out.rids.ids[0];
+ r.out.user_handle = &user_handle;
- if (!test_ChangePasswordUser2(p, mem_ctx, acct_name, domain_handle, password)) {
- ret = False;
- }
+ 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));
+ return False;
+ }
- if (!test_OemChangePasswordUser2(p, mem_ctx, acct_name, domain_handle, password)) {
- ret = False;
+ q.in.user_handle = &user_handle;
+ q.in.level = 5;
+
+ status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("QueryUserInfo failed - %s\n", nt_errstr(status));
+ return False;
+ }
+
+ printf("calling test_ChangePasswordUser3 with too early password change\n");
+
+ if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL,
+ q.out.info->info5.last_password_change, True)) {
+ ret = False;
+ }
}
/* 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)) {
+ if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, 0, True)) {
ret = False;
}
- if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password)) {
+ if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, 0, True)) {
ret = False;
}
static BOOL test_CreateUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *domain_handle,
+ struct policy_handle *user_handle_out,
enum torture_samr_choice which_ops)
{
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));
+ if (user_handle_out) {
+ *user_handle_out = user_handle;
+ } else {
+ printf("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));
ret = False;
+ }
}
}
if (NT_STATUS_IS_OK(status)) {
q.in.user_handle = &user_handle;
- q.in.level = 16;
+ q.in.level = 5;
status = dcerpc_samr_QueryUserInfo(p, user_ctx, &q);
if (!NT_STATUS_IS_OK(status)) {
q.in.level, nt_errstr(status));
ret = False;
} else {
- if ((q.out.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",
- q.out.info->info16.acct_flags,
+ if ((q.out.info->info5.acct_flags & acct_flags) != acct_flags) {
+ printf("QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n",
+ q.out.info->info5.acct_flags,
acct_flags);
ret = False;
+ }
+ switch (acct_flags) {
+ case ACB_SVRTRUST:
+ if (q.out.info->info5.primary_gid != DOMAIN_RID_DCS) {
+ printf("QuerUserInfo level 5: DC should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_DCS, q.out.info->info5.primary_gid);
+ ret = False;
+ }
+ break;
+ case ACB_WSTRUST:
+ if (q.out.info->info5.primary_gid != DOMAIN_RID_DOMAIN_MEMBERS) {
+ printf("QuerUserInfo level 5: Domain Member should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_DOMAIN_MEMBERS, q.out.info->info5.primary_gid);
+ ret = False;
+ }
+ break;
+ case ACB_NORMAL:
+ if (q.out.info->info5.primary_gid != DOMAIN_RID_USERS) {
+ printf("QuerUserInfo level 5: Users should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_USERS, q.out.info->info5.primary_gid);
+ ret = False;
+ }
+ break;
}
}
return ret;
}
-static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle)
+static BOOL check_mask(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, uint32_t rid,
+ uint32_t acct_flag_mask)
{
NTSTATUS status;
- struct samr_EnumDomainUsers r;
- uint32_t resume_handle=0;
- int i;
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ struct policy_handle user_handle;
BOOL ret = True;
- struct samr_LookupNames n;
- struct samr_LookupRids lr ;
- printf("Testing EnumDomainUsers\n");
+ printf("Testing OpenUser(%u)\n", rid);
r.in.domain_handle = handle;
- r.in.resume_handle = &resume_handle;
- r.in.acct_flags = 0;
- r.in.max_size = (uint32_t)-1;
- r.out.resume_handle = &resume_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = &user_handle;
- status = dcerpc_samr_EnumDomainUsers(p, mem_ctx, &r);
+ status = dcerpc_samr_OpenUser(p, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
- printf("EnumDomainUsers failed - %s\n", nt_errstr(status));
+ printf("OpenUser(%u) failed - %s\n", rid, nt_errstr(status));
return False;
}
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 16;
- if (!r.out.sam) {
- return False;
+ status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("QueryUserInfo level 16 failed - %s\n",
+ nt_errstr(status));
+ ret = False;
+ } else {
+ if ((acct_flag_mask & q.out.info->info16.acct_flags) == 0) {
+ printf("Server failed to filter for 0x%x, allowed 0x%x (%d) on EnumDomainUsers\n",
+ acct_flag_mask, q.out.info->info16.acct_flags, rid);
+ ret = False;
+ }
}
-
- if (r.out.sam->count == 0) {
- return True;
+
+ if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) {
+ ret = False;
}
- for (i=0;i<r.out.sam->count;i++) {
- if (!test_OpenUser(p, mem_ctx, handle, r.out.sam->entries[i].idx)) {
- ret = False;
+ return ret;
+}
+
+static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle)
+{
+ NTSTATUS status = STATUS_MORE_ENTRIES;
+ struct samr_EnumDomainUsers r;
+ uint32_t mask, resume_handle=0;
+ int i, mask_idx;
+ BOOL ret = True;
+ struct samr_LookupNames n;
+ struct samr_LookupRids lr ;
+ 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");
+
+ for (mask_idx=0;mask_idx<ARRAY_SIZE(masks);mask_idx++) {
+ r.in.domain_handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.acct_flags = mask = masks[mask_idx];
+ r.in.max_size = (uint32_t)-1;
+ r.out.resume_handle = &resume_handle;
+
+ status = dcerpc_samr_EnumDomainUsers(p, mem_ctx, &r);
+ if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
+ !NT_STATUS_IS_OK(status)) {
+ printf("EnumDomainUsers failed - %s\n", nt_errstr(status));
+ return False;
+ }
+
+ if (!r.out.sam) {
+ printf("EnumDomainUsers failed: r.out.sam unexpectedly NULL\n");
+ return False;
+ }
+
+ if (r.out.sam->count == 0) {
+ continue;
+ }
+
+ for (i=0;i<r.out.sam->count;i++) {
+ if (mask) {
+ if (!check_mask(p, mem_ctx, handle, r.out.sam->entries[i].idx, mask)) {
+ ret = False;
+ }
+ } else if (!test_OpenUser(p, mem_ctx, handle, r.out.sam->entries[i].idx)) {
+ ret = False;
+ }
}
}
return ret;
}
+#define STRING_EQUAL_QUERY(s1, s2, user) \
+ if (s1.string == NULL && s2.string != NULL && s2.string[0] == '\0') { \
+ /* odd, but valid */ \
+ } else if ((s1.string && !s2.string) || (s2.string && !s1.string) || strcmp(s1.string, s2.string)) { \
+ printf("%s mismatch for %s: %s != %s (%s)\n", \
+ #s1, user.string, s1.string, s2.string, __location__); \
+ ret = False; \
+ }
+#define INT_EQUAL_QUERY(s1, s2, user) \
+ if (s1 != s2) { \
+ printf("%s mismatch for %s: 0x%x != 0x%x (%s)\n", \
+ #s1, user.string, (unsigned int)s1, (unsigned int)s2, __location__); \
+ ret = False; \
+ }
+
+static BOOL test_each_DisplayInfo_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct samr_QueryDisplayInfo *querydisplayinfo,
+ bool *seen_testuser)
+{
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ struct policy_handle user_handle;
+ int i, ret = True;
+ NTSTATUS status;
+ r.in.domain_handle = querydisplayinfo->in.domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ for (i = 0; ; i++) {
+ switch (querydisplayinfo->in.level) {
+ case 1:
+ if (i >= querydisplayinfo->out.info.info1.count) {
+ return ret;
+ }
+ r.in.rid = querydisplayinfo->out.info.info1.entries[i].rid;
+ break;
+ case 2:
+ if (i >= querydisplayinfo->out.info.info2.count) {
+ return ret;
+ }
+ r.in.rid = querydisplayinfo->out.info.info2.entries[i].rid;
+ break;
+ case 3:
+ /* Groups */
+ case 4:
+ case 5:
+ /* 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));
+ return False;
+ }
+ }
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 21;
+ 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));
+ return False;
+ }
+
+ switch (querydisplayinfo->in.level) {
+ case 1:
+ if (seen_testuser && strcmp(q.out.info->info21.account_name.string, TEST_ACCOUNT_NAME) == 0) {
+ *seen_testuser = true;
+ }
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].full_name,
+ q.out.info->info21.full_name, q.out.info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].account_name,
+ q.out.info->info21.account_name, q.out.info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].description,
+ q.out.info->info21.description, q.out.info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].rid,
+ q.out.info->info21.rid, q.out.info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].acct_flags,
+ q.out.info->info21.acct_flags, q.out.info->info21.account_name);
+
+ break;
+ case 2:
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].account_name,
+ q.out.info->info21.account_name, q.out.info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].description,
+ q.out.info->info21.description, q.out.info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].rid,
+ q.out.info->info21.rid, q.out.info->info21.account_name);
+ INT_EQUAL_QUERY((querydisplayinfo->out.info.info2.entries[i].acct_flags & ~ACB_NORMAL),
+ q.out.info->info21.acct_flags, q.out.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",
+ q.out.info->info21.account_name.string);
+ }
+
+ if (!(q.out.info->info21.acct_flags & (ACB_WSTRUST | ACB_SVRTRUST))) {
+ printf("Found non-trust account %s in trust account listing: 0x%x 0x%x\n",
+ q.out.info->info21.account_name.string,
+ querydisplayinfo->out.info.info2.entries[i].acct_flags,
+ q.out.info->info21.acct_flags);
+ return False;
+ }
+
+ break;
+ }
+
+ if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) {
+ return False;
+ }
+ }
+ return ret;
+}
+
static BOOL test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *handle)
{
NTSTATUS status;
struct samr_QueryDisplayInfo r;
+ struct samr_QueryDomainInfo dom_info;
BOOL ret = True;
uint16_t levels[] = {1, 2, 3, 4, 5};
int i;
+ bool seen_testuser = false;
for (i=0;i<ARRAY_SIZE(levels);i++) {
printf("Testing QueryDisplayInfo level %u\n", levels[i]);
- r.in.domain_handle = handle;
- r.in.level = levels[i];
r.in.start_idx = 0;
- r.in.max_entries = 1000;
- r.in.buf_size = (uint32_t)-1;
-
- status = dcerpc_samr_QueryDisplayInfo(p, mem_ctx, &r);
+ status = STATUS_MORE_ENTRIES;
+ while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.max_entries = 2;
+ r.in.buf_size = (uint32_t)-1;
+
+ status = dcerpc_samr_QueryDisplayInfo(p, mem_ctx, &r);
+ if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) && !NT_STATUS_IS_OK(status)) {
+ printf("QueryDisplayInfo level %u failed - %s\n",
+ levels[i], nt_errstr(status));
+ ret = False;
+ }
+ switch (r.in.level) {
+ case 1:
+ if (!test_each_DisplayInfo_user(p, mem_ctx, &r, &seen_testuser)) {
+ ret = False;
+ }
+ r.in.start_idx += r.out.info.info1.count;
+ break;
+ case 2:
+ if (!test_each_DisplayInfo_user(p, mem_ctx, &r, NULL)) {
+ ret = False;
+ }
+ r.in.start_idx += r.out.info.info2.count;
+ break;
+ case 3:
+ r.in.start_idx += r.out.info.info3.count;
+ break;
+ case 4:
+ r.in.start_idx += r.out.info.info4.count;
+ break;
+ case 5:
+ r.in.start_idx += r.out.info.info5.count;
+ break;
+ }
+ }
+ dom_info.in.domain_handle = handle;
+ dom_info.in.level = 2;
+ /* Check number of users returned is correct */
+ status = dcerpc_samr_QueryDomainInfo(p, mem_ctx, &dom_info);
if (!NT_STATUS_IS_OK(status)) {
- printf("QueryDisplayInfo level %u failed - %s\n",
- levels[i], nt_errstr(status));
- ret = False;
+ printf("QueryDomainInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(status));
+ ret = False;
+ break;
+ }
+ switch (r.in.level) {
+ case 1:
+ case 4:
+ if (dom_info.out.info->info2.num_users < r.in.start_idx) {
+ printf("QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n",
+ r.in.start_idx, dom_info.out.info->info2.num_groups,
+ dom_info.out.info->info2.domain_name.string);
+ ret = False;
+ }
+ if (!seen_testuser) {
+ struct policy_handle user_handle;
+ if (NT_STATUS_IS_OK(test_OpenUser_byname(p, mem_ctx, handle, TEST_ACCOUNT_NAME, &user_handle))) {
+ printf("Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n",
+ dom_info.out.info->info2.domain_name.string);
+ ret = False;
+ test_samr_handle_Close(p, mem_ctx, &user_handle);
+ }
+ }
+ break;
+ case 3:
+ case 5:
+ if (dom_info.out.info->info2.num_groups != r.in.start_idx) {
+ printf("QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n",
+ r.in.start_idx, dom_info.out.info->info2.num_groups,
+ dom_info.out.info->info2.domain_name.string);
+ ret = False;
+ }
+
+ break;
}
+
}
return ret;
levels[i], r.out.info->info2.comment.string, domain_comment);
ret = False;
}
+ if (!r.out.info->info2.primary.string) {
+ printf("QueryDomainInfo level %u returned no PDC name\n",
+ levels[i]);
+ ret = False;
+ } else if (r.out.info->info2.role == SAMR_ROLE_DOMAIN_PDC) {
+ if (dcerpc_server_name(p) && strcasecmp_m(dcerpc_server_name(p), r.out.info->info2.primary.string) != 0) {
+ printf("QueryDomainInfo level %u returned different PDC name (%s) compared to server name (%s), despite claiming to be the PDC\n",
+ levels[i], r.out.info->info2.primary.string, dcerpc_server_name(p));
+ }
+ }
break;
case 4:
if (strcmp(r.out.info->info4.comment.string, domain_comment) != 0) {
ret = False;
}
break;
+ case 6:
+ if (!r.out.info->info6.primary.string) {
+ printf("QueryDomainInfo level %u returned no PDC name\n",
+ levels[i]);
+ ret = False;
+ }
+ break;
case 11:
if (strcmp(r.out.info->info11.info2.comment.string, domain_comment) != 0) {
printf("QueryDomainInfo level %u returned different comment (%s, expected %s)\n",
}
}
- return True;
+ return ret;
}
status = test_LookupName(p, mem_ctx, domain_handle, TEST_ACCOUNT_NAME, &rid);
if (!NT_STATUS_IS_OK(status)) {
+ printf("test_AddGroupMember looking up name " TEST_ACCOUNT_NAME " failed - %s\n", nt_errstr(status));
return False;
}
return False;
}
- if (lp_parm_bool(-1, "target", "samba4", False)) {
+ if (lp_parm_bool(-1, "torture", "samba4", False)) {
printf("skipping SetMemberAttributesOfGroup test against Samba4\n");
} else {
/* this one is quite strange. I am using random inputs in the
return True;
}
- if (NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS) ||
- NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS)) {
if (!test_DeleteGroup_byname(p, mem_ctx, domain_handle, r.in.name->string)) {
+
+ printf("CreateDomainGroup failed: Could not delete domain group %s - %s\n", r.in.name->string,
+ nt_errstr(status));
+ return False;
+ }
+ status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ if (!test_DeleteUser_byname(p, mem_ctx, 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;
}
status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
}
if (!test_AddGroupMember(p, mem_ctx, domain_handle, group_handle)) {
+ printf("CreateDomainGroup failed - %s\n", nt_errstr(status));
ret = False;
}
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;
ZERO_STRUCT(alias_handle);
+ ZERO_STRUCT(user_handle);
ZERO_STRUCT(group_handle);
ZERO_STRUCT(domain_handle);
switch (which_ops) {
case TORTURE_SAMR_USER_ATTRIBUTES:
case TORTURE_SAMR_PASSWORDS:
- ret &= test_CreateUser(p, mem_ctx, &domain_handle, which_ops);
ret &= test_CreateUser2(p, mem_ctx, &domain_handle, which_ops);
+ ret &= test_CreateUser(p, mem_ctx, &domain_handle, &user_handle, which_ops);
+ /* This test needs 'complex' users to validate */
+ ret &= test_QueryDisplayInfo(p, mem_ctx, &domain_handle);
break;
case TORTURE_SAMR_OTHER:
+ ret &= test_CreateUser(p, mem_ctx, &domain_handle, &user_handle, which_ops);
ret &= test_QuerySecurity(p, mem_ctx, &domain_handle);
ret &= test_RemoveMemberFromForeignDomain(p, mem_ctx, &domain_handle);
ret &= test_CreateAlias(p, mem_ctx, &domain_handle, &alias_handle, sid);
ret &= test_EnumDomainUsers_async(p, mem_ctx, &domain_handle);
ret &= test_EnumDomainGroups(p, mem_ctx, &domain_handle);
ret &= test_EnumDomainAliases(p, mem_ctx, &domain_handle);
- ret &= test_QueryDisplayInfo(p, mem_ctx, &domain_handle);
ret &= test_QueryDisplayInfo2(p, mem_ctx, &domain_handle);
ret &= test_QueryDisplayInfo3(p, mem_ctx, &domain_handle);
ret &= test_QueryDisplayInfo_continue(p, mem_ctx, &domain_handle);
- if (lp_parm_bool(-1, "target", "samba4", False)) {
+ if (lp_parm_bool(-1, "torture", "samba4", False)) {
printf("skipping GetDisplayEnumerationIndex test against Samba4\n");
} else {
ret &= test_GetDisplayEnumerationIndex(p, mem_ctx, &domain_handle);
break;
}
+ if (!policy_handle_empty(&user_handle) &&
+ !test_DeleteUser(p, mem_ctx, &user_handle)) {
+ ret = False;
+ }
+
if (!policy_handle_empty(&alias_handle) &&
!test_DeleteAlias(p, mem_ctx, &alias_handle)) {
ret = False;
BOOL ret = True;
struct policy_handle handle;
- status = torture_rpc_connection(torture, &p, &dcerpc_table_samr);
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
BOOL ret = True;
struct policy_handle handle;
- status = torture_rpc_connection(torture, &p, &dcerpc_table_samr);
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
BOOL ret = True;
struct policy_handle handle;
- status = torture_rpc_connection(torture, &p, &dcerpc_table_samr);
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
return False;
}