2 Unix SMB/CIFS implementation.
3 Test suite for libnet calls.
5 Copyright (C) Rafal Szczesniak 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/time.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "libnet/libnet.h"
25 #include "librpc/gen_ndr/ndr_samr_c.h"
26 #include "librpc/gen_ndr/ndr_lsa_c.h"
27 #include "torture/rpc/rpc.h"
28 #include "torture/libnet/usertest.h"
29 #include "param/param.h"
32 static bool test_cleanup(struct dcerpc_pipe
*p
, TALLOC_CTX
*mem_ctx
,
33 struct policy_handle
*domain_handle
, const char *username
)
36 struct samr_LookupNames r1
;
37 struct samr_OpenUser r2
;
38 struct samr_DeleteUser r3
;
39 struct lsa_String names
[2];
41 struct policy_handle user_handle
;
42 struct samr_Ids rids
, types
;
44 names
[0].string
= username
;
46 r1
.in
.domain_handle
= domain_handle
;
50 r1
.out
.types
= &types
;
52 printf("user account lookup '%s'\n", username
);
54 status
= dcerpc_samr_LookupNames(p
, mem_ctx
, &r1
);
55 if (!NT_STATUS_IS_OK(status
)) {
56 printf("LookupNames failed - %s\n", nt_errstr(status
));
60 rid
= r1
.out
.rids
->ids
[0];
62 r2
.in
.domain_handle
= domain_handle
;
63 r2
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
65 r2
.out
.user_handle
= &user_handle
;
67 printf("opening user account\n");
69 status
= dcerpc_samr_OpenUser(p
, mem_ctx
, &r2
);
70 if (!NT_STATUS_IS_OK(status
)) {
71 printf("OpenUser failed - %s\n", nt_errstr(status
));
75 r3
.in
.user_handle
= &user_handle
;
76 r3
.out
.user_handle
= &user_handle
;
78 printf("deleting user account\n");
80 status
= dcerpc_samr_DeleteUser(p
, mem_ctx
, &r3
);
81 if (!NT_STATUS_IS_OK(status
)) {
82 printf("DeleteUser failed - %s\n", nt_errstr(status
));
90 static bool test_opendomain(struct dcerpc_pipe
*p
, TALLOC_CTX
*mem_ctx
,
91 struct policy_handle
*handle
, struct lsa_String
*domname
)
94 struct policy_handle h
, domain_handle
;
95 struct samr_Connect r1
;
96 struct samr_LookupDomain r2
;
97 struct dom_sid2
*sid
= NULL
;
98 struct samr_OpenDomain r3
;
100 printf("connecting\n");
102 r1
.in
.system_name
= 0;
103 r1
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
104 r1
.out
.connect_handle
= &h
;
106 status
= dcerpc_samr_Connect(p
, mem_ctx
, &r1
);
107 if (!NT_STATUS_IS_OK(status
)) {
108 printf("Connect failed - %s\n", nt_errstr(status
));
112 r2
.in
.connect_handle
= &h
;
113 r2
.in
.domain_name
= domname
;
116 printf("domain lookup on %s\n", domname
->string
);
118 status
= dcerpc_samr_LookupDomain(p
, mem_ctx
, &r2
);
119 if (!NT_STATUS_IS_OK(status
)) {
120 printf("LookupDomain failed - %s\n", nt_errstr(status
));
124 r3
.in
.connect_handle
= &h
;
125 r3
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
126 r3
.in
.sid
= *r2
.out
.sid
;
127 r3
.out
.domain_handle
= &domain_handle
;
129 printf("opening domain\n");
131 status
= dcerpc_samr_OpenDomain(p
, mem_ctx
, &r3
);
132 if (!NT_STATUS_IS_OK(status
)) {
133 printf("OpenDomain failed - %s\n", nt_errstr(status
));
136 *handle
= domain_handle
;
143 static bool test_samr_close(struct dcerpc_pipe
*p
, TALLOC_CTX
*mem_ctx
,
144 struct policy_handle
*domain_handle
)
149 r
.in
.handle
= domain_handle
;
150 r
.out
.handle
= domain_handle
;
152 status
= dcerpc_samr_Close(p
, mem_ctx
, &r
);
153 if (!NT_STATUS_IS_OK(status
)) {
154 printf("Close samr domain failed - %s\n", nt_errstr(status
));
162 static bool test_lsa_close(struct dcerpc_pipe
*p
, TALLOC_CTX
*mem_ctx
,
163 struct policy_handle
*domain_handle
)
168 r
.in
.handle
= domain_handle
;
169 r
.out
.handle
= domain_handle
;
171 status
= dcerpc_lsa_Close(p
, mem_ctx
, &r
);
172 if (!NT_STATUS_IS_OK(status
)) {
173 printf("Close lsa domain failed - %s\n", nt_errstr(status
));
181 static bool test_createuser(struct dcerpc_pipe
*p
, TALLOC_CTX
*mem_ctx
,
182 struct policy_handle
*handle
, const char* user
)
185 struct policy_handle user_handle
;
186 struct lsa_String username
;
187 struct samr_CreateUser r1
;
188 struct samr_Close r2
;
191 username
.string
= user
;
193 r1
.in
.domain_handle
= handle
;
194 r1
.in
.account_name
= &username
;
195 r1
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
196 r1
.out
.user_handle
= &user_handle
;
197 r1
.out
.rid
= &user_rid
;
199 printf("creating user '%s'\n", username
.string
);
201 status
= dcerpc_samr_CreateUser(p
, mem_ctx
, &r1
);
202 if (!NT_STATUS_IS_OK(status
)) {
203 printf("CreateUser failed - %s\n", nt_errstr(status
));
205 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
206 printf("User (%s) already exists - attempting to delete and recreate account again\n", user
);
207 if (!test_cleanup(p
, mem_ctx
, handle
, TEST_USERNAME
)) {
211 printf("creating user account\n");
213 status
= dcerpc_samr_CreateUser(p
, mem_ctx
, &r1
);
214 if (!NT_STATUS_IS_OK(status
)) {
215 printf("CreateUser failed - %s\n", nt_errstr(status
));
223 r2
.in
.handle
= &user_handle
;
224 r2
.out
.handle
= &user_handle
;
226 printf("closing user '%s'\n", username
.string
);
228 status
= dcerpc_samr_Close(p
, mem_ctx
, &r2
);
229 if (!NT_STATUS_IS_OK(status
)) {
230 printf("Close failed - %s\n", nt_errstr(status
));
238 bool torture_createuser(struct torture_context
*torture
)
242 struct libnet_context
*ctx
;
243 struct libnet_CreateUser req
;
246 mem_ctx
= talloc_init("test_createuser");
248 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
249 ctx
->cred
= cmdline_credentials
;
251 req
.in
.user_name
= TEST_USERNAME
;
252 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
253 req
.out
.error_string
= NULL
;
255 status
= libnet_CreateUser(ctx
, mem_ctx
, &req
);
256 if (!NT_STATUS_IS_OK(status
)) {
257 printf("libnet_CreateUser call failed: %s\n", nt_errstr(status
));
262 if (!test_cleanup(ctx
->samr
.pipe
, mem_ctx
, &ctx
->samr
.handle
, TEST_USERNAME
)) {
263 printf("cleanup failed\n");
268 if (!test_samr_close(ctx
->samr
.pipe
, mem_ctx
, &ctx
->samr
.handle
)) {
269 printf("domain close failed\n");
275 talloc_free(mem_ctx
);
280 bool torture_deleteuser(struct torture_context
*torture
)
283 struct dcerpc_pipe
*p
;
284 TALLOC_CTX
*prep_mem_ctx
, *mem_ctx
;
285 struct policy_handle h
;
286 struct lsa_String domain_name
;
287 const char *name
= TEST_USERNAME
;
288 struct libnet_context
*ctx
;
289 struct libnet_DeleteUser req
;
292 prep_mem_ctx
= talloc_init("prepare test_deleteuser");
294 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
295 ctx
->cred
= cmdline_credentials
;
297 req
.in
.user_name
= TEST_USERNAME
;
298 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
300 status
= torture_rpc_connection(torture
,
303 if (!NT_STATUS_IS_OK(status
)) {
308 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
309 if (!test_opendomain(p
, prep_mem_ctx
, &h
, &domain_name
)) {
314 if (!test_createuser(p
, prep_mem_ctx
, &h
, name
)) {
319 mem_ctx
= talloc_init("test_deleteuser");
321 status
= libnet_DeleteUser(ctx
, mem_ctx
, &req
);
322 if (!NT_STATUS_IS_OK(status
)) {
323 printf("libnet_DeleteUser call failed: %s\n", nt_errstr(status
));
327 talloc_free(mem_ctx
);
331 talloc_free(prep_mem_ctx
);
337 Generate testing set of random changes
340 static void set_test_changes(TALLOC_CTX
*mem_ctx
, struct libnet_ModifyUser
*r
,
341 int num_changes
, char **user_name
, enum test_fields req_change
)
343 const char* logon_scripts
[] = { "start_login.cmd", "login.bat", "start.cmd" };
344 const char* home_dirs
[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
345 const char* home_drives
[] = { "H:", "z:", "I:", "J:", "n:" };
346 const uint32_t flags
[] = { (ACB_DISABLED
| ACB_NORMAL
| ACB_PW_EXPIRED
),
347 (ACB_NORMAL
| ACB_PWNOEXP
),
348 (ACB_NORMAL
| ACB_PW_EXPIRED
) };
349 const char *homedir
, *homedrive
, *logonscript
;
353 printf("Fields to change: [");
355 for (i
= 0; i
< num_changes
&& i
< FIELDS_NUM
; i
++) {
358 testfld
= (req_change
== none
) ? (random() % FIELDS_NUM
) : req_change
;
360 /* get one in case we hit time field this time */
361 gettimeofday(&now
, NULL
);
365 continue_if_field_set(r
->in
.account_name
);
366 r
->in
.account_name
= talloc_asprintf(mem_ctx
, TEST_CHG_ACCOUNTNAME
,
367 (int)(random() % 100));
368 fldname
= "account_name";
370 /* update the test's user name in case it's about to change */
371 *user_name
= talloc_strdup(mem_ctx
, r
->in
.account_name
);
375 continue_if_field_set(r
->in
.full_name
);
376 r
->in
.full_name
= talloc_asprintf(mem_ctx
, TEST_CHG_FULLNAME
,
377 (unsigned int)random(), (unsigned int)random());
378 fldname
= "full_name";
382 continue_if_field_set(r
->in
.description
);
383 r
->in
.description
= talloc_asprintf(mem_ctx
, TEST_CHG_DESCRIPTION
,
385 fldname
= "description";
389 continue_if_field_set(r
->in
.home_directory
);
390 homedir
= home_dirs
[random() % ARRAY_SIZE(home_dirs
)];
391 r
->in
.home_directory
= talloc_strdup(mem_ctx
, homedir
);
392 fldname
= "home_dir";
396 continue_if_field_set(r
->in
.home_drive
);
397 homedrive
= home_drives
[random() % ARRAY_SIZE(home_drives
)];
398 r
->in
.home_drive
= talloc_strdup(mem_ctx
, homedrive
);
399 fldname
= "home_drive";
403 continue_if_field_set(r
->in
.comment
);
404 r
->in
.comment
= talloc_asprintf(mem_ctx
, TEST_CHG_COMMENT
,
405 (unsigned long)random(), (unsigned long)random());
410 continue_if_field_set(r
->in
.logon_script
);
411 logonscript
= logon_scripts
[random() % ARRAY_SIZE(logon_scripts
)];
412 r
->in
.logon_script
= talloc_strdup(mem_ctx
, logonscript
);
413 fldname
= "logon_script";
417 continue_if_field_set(r
->in
.profile_path
);
418 r
->in
.profile_path
= talloc_asprintf(mem_ctx
, TEST_CHG_PROFILEPATH
,
419 (unsigned long)random(), (unsigned int)random());
420 fldname
= "profile_path";
424 continue_if_field_set(r
->in
.acct_expiry
);
425 now
= timeval_add(&now
, (random() % (31*24*60*60)), 0);
426 r
->in
.acct_expiry
= (struct timeval
*)talloc_memdup(mem_ctx
, &now
, sizeof(now
));
427 fldname
= "acct_expiry";
431 continue_if_field_set(r
->in
.acct_flags
);
432 r
->in
.acct_flags
= flags
[random() % ARRAY_SIZE(flags
)];
433 fldname
= "acct_flags";
437 fldname
= "unknown_field";
440 printf(((i
< num_changes
- 1) ? "%s," : "%s"), fldname
);
442 /* disable requested field (it's supposed to be the only one used) */
443 if (req_change
!= none
) req_change
= none
;
450 #define TEST_STR_FLD(fld) \
451 if (!strequal(req.in.fld, user_req.out.fld)) { \
452 printf("failed to change '%s'\n", #fld); \
457 #define TEST_TIME_FLD(fld) \
458 if (timeval_compare(req.in.fld, user_req.out.fld)) { \
459 printf("failed to change '%s'\n", #fld); \
464 #define TEST_NUM_FLD(fld) \
465 if (req.in.fld != user_req.out.fld) { \
466 printf("failed to change '%s'\n", #fld); \
472 bool torture_modifyuser(struct torture_context
*torture
)
475 struct dcerpc_binding
*binding
;
476 struct dcerpc_pipe
*p
;
477 TALLOC_CTX
*prep_mem_ctx
;
478 struct policy_handle h
;
479 struct lsa_String domain_name
;
481 struct libnet_context
*ctx
;
482 struct libnet_ModifyUser req
;
483 struct libnet_UserInfo user_req
;
487 prep_mem_ctx
= talloc_init("prepare test_deleteuser");
489 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
490 ctx
->cred
= cmdline_credentials
;
492 status
= torture_rpc_connection(torture
,
495 if (!NT_STATUS_IS_OK(status
)) {
500 name
= talloc_strdup(prep_mem_ctx
, TEST_USERNAME
);
502 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
503 if (!test_opendomain(p
, prep_mem_ctx
, &h
, &domain_name
)) {
508 if (!test_createuser(p
, prep_mem_ctx
, &h
, name
)) {
513 status
= torture_rpc_binding(torture
, &binding
);
514 if (!NT_STATUS_IS_OK(status
)) {
519 printf("Testing change of all fields - each single one in turn\n");
521 for (fld
= 1; fld
< FIELDS_NUM
- 1; fld
++) {
523 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
524 req
.in
.user_name
= name
;
526 set_test_changes(torture
, &req
, 1, &name
, fld
);
528 status
= libnet_ModifyUser(ctx
, torture
, &req
);
529 if (!NT_STATUS_IS_OK(status
)) {
530 printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status
));
535 ZERO_STRUCT(user_req
);
536 user_req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
537 user_req
.in
.data
.user_name
= name
;
538 user_req
.in
.level
= USER_INFO_BY_NAME
;
540 status
= libnet_UserInfo(ctx
, torture
, &user_req
);
541 if (!NT_STATUS_IS_OK(status
)) {
542 printf("libnet_UserInfo call failed: %s\n", nt_errstr(status
));
548 case account_name
: TEST_STR_FLD(account_name
);
550 case full_name
: TEST_STR_FLD(full_name
);
552 case comment
: TEST_STR_FLD(comment
);
554 case description
: TEST_STR_FLD(description
);
556 case home_directory
: TEST_STR_FLD(home_directory
);
558 case home_drive
: TEST_STR_FLD(home_drive
);
560 case logon_script
: TEST_STR_FLD(logon_script
);
562 case profile_path
: TEST_STR_FLD(profile_path
);
564 case acct_expiry
: TEST_TIME_FLD(acct_expiry
);
566 case acct_flags
: TEST_NUM_FLD(acct_flags
);
572 if (fld
== account_name
) {
573 /* restore original testing username - it's useful when test fails
574 because it prevents from problems with recreating account */
576 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
577 req
.in
.user_name
= name
;
578 req
.in
.account_name
= TEST_USERNAME
;
580 status
= libnet_ModifyUser(ctx
, torture
, &req
);
581 if (!NT_STATUS_IS_OK(status
)) {
582 printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status
));
587 name
= talloc_strdup(torture
, TEST_USERNAME
);
592 if (!test_cleanup(ctx
->samr
.pipe
, torture
, &ctx
->samr
.handle
, name
)) {
593 printf("cleanup failed\n");
598 if (!test_samr_close(ctx
->samr
.pipe
, torture
, &ctx
->samr
.handle
)) {
599 printf("domain close failed\n");
605 talloc_free(prep_mem_ctx
);
610 bool torture_userinfo_api(struct torture_context
*torture
)
612 const char *name
= TEST_USERNAME
;
615 TALLOC_CTX
*mem_ctx
= NULL
, *prep_mem_ctx
;
616 struct libnet_context
*ctx
;
617 struct dcerpc_pipe
*p
;
618 struct policy_handle h
;
619 struct lsa_String domain_name
;
620 struct libnet_UserInfo req
;
622 prep_mem_ctx
= talloc_init("prepare torture user info");
624 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
625 ctx
->cred
= cmdline_credentials
;
627 status
= torture_rpc_connection(torture
,
630 if (!NT_STATUS_IS_OK(status
)) {
634 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
635 if (!test_opendomain(p
, prep_mem_ctx
, &h
, &domain_name
)) {
640 if (!test_createuser(p
, prep_mem_ctx
, &h
, name
)) {
645 mem_ctx
= talloc_init("torture user info");
649 req
.in
.domain_name
= domain_name
.string
;
650 req
.in
.data
.user_name
= name
;
651 req
.in
.level
= USER_INFO_BY_NAME
;
653 status
= libnet_UserInfo(ctx
, mem_ctx
, &req
);
654 if (!NT_STATUS_IS_OK(status
)) {
655 printf("libnet_UserInfo call failed: %s\n", nt_errstr(status
));
657 talloc_free(mem_ctx
);
661 if (!test_cleanup(ctx
->samr
.pipe
, mem_ctx
, &ctx
->samr
.handle
, TEST_USERNAME
)) {
662 printf("cleanup failed\n");
667 if (!test_samr_close(ctx
->samr
.pipe
, mem_ctx
, &ctx
->samr
.handle
)) {
668 printf("domain close failed\n");
675 talloc_free(mem_ctx
);
680 bool torture_userlist(struct torture_context
*torture
)
684 TALLOC_CTX
*mem_ctx
= NULL
;
685 struct libnet_context
*ctx
;
686 struct lsa_String domain_name
;
687 struct libnet_UserList req
;
690 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
691 ctx
->cred
= cmdline_credentials
;
693 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
694 mem_ctx
= talloc_init("torture user list");
698 printf("listing user accounts:\n");
702 req
.in
.domain_name
= domain_name
.string
;
703 req
.in
.page_size
= 128;
704 req
.in
.resume_index
= req
.out
.resume_index
;
706 status
= libnet_UserList(ctx
, mem_ctx
, &req
);
707 if (!NT_STATUS_IS_OK(status
) &&
708 !NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) break;
710 for (i
= 0; i
< req
.out
.count
; i
++) {
711 printf("\tuser: %s, sid=%s\n",
712 req
.out
.users
[i
].username
, req
.out
.users
[i
].sid
);
715 } while (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
));
717 if (!(NT_STATUS_IS_OK(status
) ||
718 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
))) {
719 printf("libnet_UserList call failed: %s\n", nt_errstr(status
));
724 if (!test_samr_close(ctx
->samr
.pipe
, mem_ctx
, &ctx
->samr
.handle
)) {
725 printf("samr domain close failed\n");
730 if (!test_lsa_close(ctx
->lsa
.pipe
, mem_ctx
, &ctx
->lsa
.handle
)) {
731 printf("lsa domain close failed\n");
738 talloc_free(mem_ctx
);