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 "lib/cmdline/popt_common.h"
#include "libnet/libnet.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
#include "torture/torture.h"
#include "torture/rpc/rpc.h"
+#include "torture/libnet/usertest.h"
+#include "param/param.h"
-#define TEST_USERNAME "libnetusertest"
-
static BOOL test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *domain_handle, const char *username)
{
struct samr_LookupNames r1;
struct samr_OpenUser r2;
struct samr_DeleteUser r3;
- struct samr_Close r4;
struct lsa_String names[2];
uint32_t rid;
struct policy_handle user_handle;
return False;
}
- r4.in.handle = domain_handle;
- r4.out.handle = domain_handle;
-
- status = dcerpc_samr_Close(p, mem_ctx, &r4);
- if (!NT_STATUS_IS_OK(status)) {
- printf("Close failed - %s\n", nt_errstr(status));
- return False;
- }
-
return True;
}
}
+static BOOL test_samr_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct samr_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_samr_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close samr domain failed - %s\n", nt_errstr(status));
+ return False;
+ }
+
+ return True;
+}
+
+
+static BOOL test_lsa_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct lsa_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_lsa_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close lsa domain failed - %s\n", nt_errstr(status));
+ return False;
+ }
+
+ return True;
+}
+
+
static BOOL test_createuser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *handle, const char* user)
{
BOOL torture_createuser(struct torture_context *torture)
{
NTSTATUS status;
- const char *binding;
TALLOC_CTX *mem_ctx;
struct libnet_context *ctx;
struct libnet_CreateUser req;
+ BOOL ret = True;
mem_ctx = talloc_init("test_createuser");
- binding = lp_parm_string(-1, "torture", "binding");
ctx = libnet_context_init(NULL);
ctx->cred = cmdline_credentials;
req.in.user_name = TEST_USERNAME;
- req.in.domain_name = lp_workgroup();
+ req.in.domain_name = lp_workgroup(global_loadparm);
req.out.error_string = NULL;
status = libnet_CreateUser(ctx, mem_ctx, &req);
if (!NT_STATUS_IS_OK(status)) {
printf("libnet_CreateUser call failed: %s\n", nt_errstr(status));
- return False;
+ ret = False;
+ goto done;
}
- if (!test_cleanup(ctx->samr_pipe, mem_ctx, &ctx->domain.handle, TEST_USERNAME)) {
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
printf("cleanup failed\n");
- return False;
+ ret = False;
+ goto done;
}
- return True;
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = False;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
}
BOOL torture_deleteuser(struct torture_context *torture)
{
NTSTATUS status;
- const char *binding;
struct dcerpc_pipe *p;
TALLOC_CTX *prep_mem_ctx, *mem_ctx;
struct policy_handle h;
BOOL ret = True;
prep_mem_ctx = talloc_init("prepare test_deleteuser");
- binding = lp_parm_string(-1, "torture", "binding");
ctx = libnet_context_init(NULL);
ctx->cred = cmdline_credentials;
req.in.user_name = TEST_USERNAME;
- req.in.domain_name = lp_workgroup();
+ req.in.domain_name = lp_workgroup(global_loadparm);
- status = torture_rpc_connection(prep_mem_ctx,
+ status = torture_rpc_connection(torture,
&p,
- &dcerpc_table_samr);
+ &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
- return False;
+ ret = False;
+ goto done;
}
- domain_name.string = lp_workgroup();
+ domain_name.string = lp_workgroup(global_loadparm);
if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
ret = False;
goto done;
status = libnet_DeleteUser(ctx, mem_ctx, &req);
if (!NT_STATUS_IS_OK(status)) {
printf("libnet_DeleteUser call failed: %s\n", nt_errstr(status));
- return False;
+ ret = False;
}
+ talloc_free(mem_ctx);
+
done:
+ talloc_free(ctx);
talloc_free(prep_mem_ctx);
- talloc_free(mem_ctx);
return ret;
}
Generate testing set of random changes
*/
-#define TEST_CHG_ACCOUNTNAME "newlibnetusertest%02d"
-#define TEST_CHG_DESCRIPTION "Sample description %ld"
-#define TEST_CHG_FULLNAME "First%04x Last%04x"
-#define TEST_CHG_COMMENT "Comment[%04lu%04lu]"
-#define TEST_CHG_PROFILEPATH "\\\\srv%04ld\\profile%02u\\prof"
-
-#define continue_if_field_set(field) \
- if (field != 0) { \
- i--; \
- continue; \
- }
-
-static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, int num_changes)
+static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r,
+ int num_changes, char **user_name, enum test_fields req_change)
{
- enum fields { account_name = 0, full_name, description, home_directory, home_drive,
- comment, logon_script, profile_path, acct_expiry, allow_password_change,
- force_password_change, last_logon, last_logoff, last_password_change };
- const int num_fields = 14;
-
const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
const char *homedir, *homedrive, *logonscript;
struct timeval now;
- int i, randval;
+ int i, testfld;
srandom((unsigned)time(NULL));
printf("Fields to change: [");
- for (i = 0; i < num_changes && i < num_fields; i++) {
+ for (i = 0; i < num_changes && i < FIELDS_NUM; i++) {
const char *fldname;
- randval = random() % num_fields;
+
+ testfld = (req_change == none) ? (random() % FIELDS_NUM) : req_change;
/* get one in case we hit time field this time */
gettimeofday(&now, NULL);
- switch (randval) {
+ switch (testfld) {
case account_name:
continue_if_field_set(r->in.account_name);
r->in.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
- (int)random());
+ (int)(random() % 100));
fldname = "account_name";
+
+ /* update the test's user name in case it's about to change */
+ *user_name = talloc_strdup(mem_ctx, r->in.account_name);
break;
case full_name:
case acct_expiry:
continue_if_field_set(r->in.acct_expiry);
now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.acct_expiry = talloc_memdup(mem_ctx, &now, sizeof(now));
+ r->in.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now));
fldname = "acct_expiry";
break;
- case allow_password_change:
- continue_if_field_set(r->in.allow_password_change);
- now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.allow_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
- fldname = "allow_password_change";
- break;
-
- case force_password_change:
- continue_if_field_set(r->in.force_password_change);
- now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.force_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
- fldname = "force_password_change";
- break;
-
- case last_logon:
- continue_if_field_set(r->in.last_logon);
- now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.last_logon = talloc_memdup(mem_ctx, &now, sizeof(now));
- fldname = "last_logon";
- break;
-
- case last_logoff:
- continue_if_field_set(r->in.last_logoff);
- now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.last_logoff = talloc_memdup(mem_ctx, &now, sizeof(now));
- fldname = "last_logoff";
- break;
-
- case last_password_change:
- continue_if_field_set(r->in.last_password_change);
- now = timeval_add(&now, (random() % (31*24*60*60)), 0);
- r->in.last_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
- fldname = "last_password_change";
- break;
+ default:
+ fldname = "unknown_field";
}
printf(((i < num_changes - 1) ? "%s," : "%s"), fldname);
+
+ /* disable requested field (it's supposed to be the only one used) */
+ if (req_change != none) req_change = none;
}
printf("]\n");
}
+#define TEST_STR_FLD(fld) \
+ if (!strequal(req.in.fld, user_req.out.fld)) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = False; \
+ goto cleanup; \
+ }
+
+#define TEST_TIME_FLD(fld) \
+ if (timeval_compare(req.in.fld, user_req.out.fld)) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = False; \
+ goto cleanup; \
+ }
+
+#define TEST_NUM_FLD(fld) \
+ if (req.in.fld != user_req.out.fld) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = False; \
+ goto cleanup; \
+ }
+
+
BOOL torture_modifyuser(struct torture_context *torture)
{
NTSTATUS status;
- const char *binding;
struct dcerpc_binding *bind;
struct dcerpc_pipe *p;
TALLOC_CTX *prep_mem_ctx, *mem_ctx;
struct policy_handle h;
struct lsa_String domain_name;
- const char *name = TEST_USERNAME;
+ char *name;
struct libnet_context *ctx;
struct libnet_ModifyUser req;
+ struct libnet_UserInfo user_req;
+ int fld;
BOOL ret = True;
prep_mem_ctx = talloc_init("prepare test_deleteuser");
- binding = lp_parm_string(-1, "torture", "binding");
ctx = libnet_context_init(NULL);
ctx->cred = cmdline_credentials;
- status = torture_rpc_connection(prep_mem_ctx,
+ status = torture_rpc_connection(torture,
&p,
- &dcerpc_table_samr);
+ &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
- return False;
+ ret = False;
+ goto done;
}
- domain_name.string = lp_workgroup();
+ name = talloc_strdup(prep_mem_ctx, TEST_USERNAME);
+
+ domain_name.string = lp_workgroup(global_loadparm);
if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
ret = False;
goto done;
mem_ctx = talloc_init("test_modifyuser");
- status = dcerpc_parse_binding(mem_ctx, binding, &bind);
+ status = torture_rpc_binding(mem_ctx, &bind);
if (!NT_STATUS_IS_OK(status)) {
ret = False;
goto done;
}
- ZERO_STRUCT(req);
- req.in.user_name = TEST_USERNAME;
- req.in.domain_name = lp_workgroup();
+ printf("Testing change of all fields - each single one in turn\n");
+
+ for (fld = 1; fld < FIELDS_NUM - 1; fld++) {
+ ZERO_STRUCT(req);
+ req.in.domain_name = lp_workgroup(global_loadparm);
+ req.in.user_name = name;
+
+ set_test_changes(mem_ctx, &req, 1, &name, fld);
+
+ status = libnet_ModifyUser(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
+ ret = False;
+ continue;
+ }
- printf("Testing change of a single field\n");
- set_test_changes(mem_ctx, &req, 1);
+ ZERO_STRUCT(user_req);
+ user_req.in.domain_name = lp_workgroup(global_loadparm);
+ user_req.in.user_name = name;
- status = libnet_ModifyUser(ctx, mem_ctx, &req);
+ status = libnet_UserInfo(ctx, mem_ctx, &user_req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = False;
+ continue;
+ }
+
+ switch (fld) {
+ case account_name: TEST_STR_FLD(account_name);
+ break;
+ case full_name: TEST_STR_FLD(full_name);
+ break;
+ case comment: TEST_STR_FLD(comment);
+ break;
+ case description: TEST_STR_FLD(description);
+ break;
+ case home_directory: TEST_STR_FLD(home_directory);
+ break;
+ case home_drive: TEST_STR_FLD(home_drive);
+ break;
+ case logon_script: TEST_STR_FLD(logon_script);
+ break;
+ case profile_path: TEST_STR_FLD(profile_path);
+ break;
+ case acct_expiry: TEST_TIME_FLD(acct_expiry);
+ break;
+ case acct_flags: TEST_NUM_FLD(acct_flags);
+ break;
+ default:
+ break;
+ }
+
+ if (fld == account_name) {
+ /* restore original testing username - it's useful when test fails
+ because it prevents from problems with recreating account */
+ ZERO_STRUCT(req);
+ req.in.domain_name = lp_workgroup(global_loadparm);
+ req.in.user_name = name;
+ req.in.account_name = TEST_USERNAME;
+
+ status = libnet_ModifyUser(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
+ talloc_free(mem_ctx);
+ ret = False;
+ goto done;
+ }
+
+ name = talloc_strdup(mem_ctx, TEST_USERNAME);
+ }
+ }
+
+cleanup:
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, name)) {
+ printf("cleanup failed\n");
+ ret = False;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = False;
+ }
+
+ talloc_free(mem_ctx);
+
+done:
+ talloc_free(ctx);
+ talloc_free(prep_mem_ctx);
+ return ret;
+}
+
+
+BOOL torture_userinfo_api(struct torture_context *torture)
+{
+ const char *name = TEST_USERNAME;
+ BOOL ret = True;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL, *prep_mem_ctx;
+ struct libnet_context *ctx;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct libnet_UserInfo req;
+
+ prep_mem_ctx = talloc_init("prepare torture user info");
+
+ ctx = libnet_context_init(NULL);
+ ctx->cred = cmdline_credentials;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
if (!NT_STATUS_IS_OK(status)) {
- printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
return False;
}
- if (!test_cleanup(ctx->samr_pipe, mem_ctx, &ctx->domain.handle, TEST_USERNAME)) {
+ domain_name.string = lp_workgroup(global_loadparm);
+ if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
+ ret = False;
+ goto done;
+ }
+
+ if (!test_createuser(p, prep_mem_ctx, &h, name)) {
+ ret = False;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("torture user info");
+
+ ZERO_STRUCT(req);
+
+ req.in.domain_name = domain_name.string;
+ req.in.user_name = name;
+
+ status = libnet_UserInfo(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = False;
+ talloc_free(mem_ctx);
+ goto done;
+ }
+
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
printf("cleanup failed\n");
- return False;
+ ret = False;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = False;
}
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+BOOL torture_userlist(struct torture_context *torture)
+{
+ BOOL ret = True;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct libnet_UserList req;
+ int i;
+
+ ctx = libnet_context_init(NULL);
+ ctx->cred = cmdline_credentials;
+
+ domain_name.string = lp_workgroup(global_loadparm);
+ mem_ctx = talloc_init("torture user list");
+
+ ZERO_STRUCT(req);
+
+ printf("listing user accounts:\n");
+
+ do {
+
+ req.in.domain_name = domain_name.string;
+ req.in.page_size = 128;
+ req.in.resume_index = req.out.resume_index;
+
+ status = libnet_UserList(ctx, mem_ctx, &req);
+
+ for (i = 0; i < req.out.count; i++) {
+ printf("\tuser: %s, sid=%s\n",
+ req.out.users[i].username, req.out.users[i].sid);
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (!(NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))) {
+ printf("libnet_UserList call failed: %s\n", nt_errstr(status));
+ ret = False;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("samr domain close failed\n");
+ ret = False;
+ goto done;
+ }
+
+ if (!test_lsa_close(ctx->lsa.pipe, mem_ctx, &ctx->lsa.handle)) {
+ printf("lsa domain close failed\n");
+ ret = False;
+ }
+
+ talloc_free(ctx);
+
done:
- talloc_free(prep_mem_ctx);
talloc_free(mem_ctx);
return ret;
}