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/torture_rpc.h"
28 #include "torture/libnet/usertest.h"
29 #include "torture/libnet/proto.h"
30 #include "param/param.h"
31 #include "lib/ldb_wrap.h"
35 * Find out user's samAccountName for given
36 * user RDN. We need samAccountName value
37 * when deleting users.
39 static bool _get_account_name_for_user_rdn(struct torture_context
*tctx
,
40 struct dcerpc_binding_handle
*b
,
43 const char **_account_name
)
46 struct ldb_context
*ldb
;
49 struct dcerpc_pipe
*p
= talloc_get_type_abort(b
->private_data
, struct dcerpc_pipe
);
51 struct ldb_result
*ldb_res
;
52 const char *account_name
= NULL
;
53 static const char *attrs
[] = {
58 tmp_ctx
= talloc_new(tctx
);
59 torture_assert(tctx
, tmp_ctx
!= NULL
, "Failed to create temporary mem context");
61 url
= talloc_asprintf(tmp_ctx
, "ldap://%s/", p
->binding
->target_hostname
);
62 torture_assert_goto(tctx
, url
!= NULL
, test_res
, done
, "Failed to allocate URL for ldb");
64 ldb
= ldb_wrap_connect(tmp_ctx
,
65 tctx
->ev
, tctx
->lp_ctx
,
66 url
, NULL
, cmdline_credentials
, 0);
67 torture_assert_goto(tctx
, ldb
!= NULL
, test_res
, done
, "Failed to make LDB connection");
69 ldb_ret
= ldb_search(ldb
, tmp_ctx
, &ldb_res
,
70 ldb_get_default_basedn(ldb
), LDB_SCOPE_SUBTREE
,
72 "(&(objectClass=user)(name=%s))", user_rdn
);
73 if (LDB_SUCCESS
== ldb_ret
&& 1 == ldb_res
->count
) {
74 account_name
= ldb_msg_find_attr_as_string(ldb_res
->msgs
[0], "samAccountName", NULL
);
77 /* return user_rdn by default */
79 account_name
= user_rdn
;
82 /* duplicate memory in parent context */
83 *_account_name
= talloc_strdup(mem_ctx
, account_name
);
91 * Deletes a user account when given user RDN name
93 * @param username RDN for the user to be deleted
95 static bool test_cleanup(struct torture_context
*tctx
,
96 struct dcerpc_binding_handle
*b
, TALLOC_CTX
*mem_ctx
,
97 struct policy_handle
*domain_handle
, const char *username
)
99 struct samr_LookupNames r1
;
100 struct samr_OpenUser r2
;
101 struct samr_DeleteUser r3
;
102 struct lsa_String names
[2];
104 struct policy_handle user_handle
;
105 struct samr_Ids rids
, types
;
106 const char *account_name
;
108 if (!_get_account_name_for_user_rdn(tctx
, b
, username
, mem_ctx
, &account_name
)) {
109 torture_result(tctx
, TORTURE_FAIL
,
110 __location__
": Failed to find samAccountName for %s", username
);
114 names
[0].string
= account_name
;
116 r1
.in
.domain_handle
= domain_handle
;
120 r1
.out
.types
= &types
;
122 torture_comment(tctx
, "user account lookup '%s'\n", account_name
);
124 torture_assert_ntstatus_ok(tctx
,
125 dcerpc_samr_LookupNames_r(b
, mem_ctx
, &r1
),
126 "LookupNames failed");
127 torture_assert_ntstatus_ok(tctx
, r1
.out
.result
,
128 "LookupNames failed");
130 rid
= r1
.out
.rids
->ids
[0];
132 r2
.in
.domain_handle
= domain_handle
;
133 r2
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
135 r2
.out
.user_handle
= &user_handle
;
137 torture_comment(tctx
, "opening user account\n");
139 torture_assert_ntstatus_ok(tctx
,
140 dcerpc_samr_OpenUser_r(b
, mem_ctx
, &r2
),
142 torture_assert_ntstatus_ok(tctx
, r2
.out
.result
,
145 r3
.in
.user_handle
= &user_handle
;
146 r3
.out
.user_handle
= &user_handle
;
148 torture_comment(tctx
, "deleting user account\n");
150 torture_assert_ntstatus_ok(tctx
,
151 dcerpc_samr_DeleteUser_r(b
, mem_ctx
, &r3
),
152 "DeleteUser failed");
153 torture_assert_ntstatus_ok(tctx
, r3
.out
.result
,
154 "DeleteUser failed");
160 static bool test_lsa_close(struct torture_context
*tctx
,
161 struct dcerpc_binding_handle
*b
, TALLOC_CTX
*mem_ctx
,
162 struct policy_handle
*domain_handle
)
166 r
.in
.handle
= domain_handle
;
167 r
.out
.handle
= domain_handle
;
169 torture_assert_ntstatus_ok(tctx
,
170 dcerpc_lsa_Close_r(b
, mem_ctx
, &r
),
171 "Close lsa domain failed");
172 torture_assert_ntstatus_ok(tctx
, r
.out
.result
,
173 "Close lsa domain failed");
179 bool torture_createuser(struct torture_context
*torture
)
183 struct libnet_context
*ctx
;
184 struct libnet_CreateUser req
;
187 mem_ctx
= talloc_init("test_createuser");
189 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
190 ctx
->cred
= cmdline_credentials
;
192 req
.in
.user_name
= TEST_USERNAME
;
193 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
194 req
.out
.error_string
= NULL
;
196 status
= libnet_CreateUser(ctx
, mem_ctx
, &req
);
197 if (!NT_STATUS_IS_OK(status
)) {
198 torture_comment(torture
, "libnet_CreateUser call failed: %s\n", nt_errstr(status
));
203 if (!test_cleanup(torture
, ctx
->samr
.pipe
->binding_handle
, mem_ctx
, &ctx
->samr
.handle
, TEST_USERNAME
)) {
204 torture_comment(torture
, "cleanup failed\n");
209 if (!test_samr_close_handle(torture
,
210 ctx
->samr
.pipe
->binding_handle
, mem_ctx
, &ctx
->samr
.handle
)) {
211 torture_comment(torture
, "domain close failed\n");
217 talloc_free(mem_ctx
);
222 bool torture_deleteuser(struct torture_context
*torture
)
225 struct dcerpc_pipe
*p
;
226 TALLOC_CTX
*prep_mem_ctx
, *mem_ctx
;
227 struct policy_handle h
;
228 struct lsa_String domain_name
;
229 const char *name
= TEST_USERNAME
;
230 struct libnet_context
*ctx
;
231 struct libnet_DeleteUser req
;
234 prep_mem_ctx
= talloc_init("prepare test_deleteuser");
236 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
237 ctx
->cred
= cmdline_credentials
;
239 req
.in
.user_name
= TEST_USERNAME
;
240 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
242 status
= torture_rpc_connection(torture
,
245 if (!NT_STATUS_IS_OK(status
)) {
250 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
251 if (!test_domain_open(torture
, p
->binding_handle
, &domain_name
, prep_mem_ctx
, &h
, NULL
)) {
256 if (!test_user_create(torture
, p
->binding_handle
, prep_mem_ctx
, &h
, name
, NULL
)) {
261 mem_ctx
= talloc_init("test_deleteuser");
263 status
= libnet_DeleteUser(ctx
, mem_ctx
, &req
);
264 if (!NT_STATUS_IS_OK(status
)) {
265 torture_comment(torture
, "libnet_DeleteUser call failed: %s\n", nt_errstr(status
));
269 talloc_free(mem_ctx
);
273 talloc_free(prep_mem_ctx
);
279 Generate testing set of random changes
282 static void set_test_changes(struct torture_context
*tctx
,
283 TALLOC_CTX
*mem_ctx
, struct libnet_ModifyUser
*r
,
284 int num_changes
, char **user_name
, enum test_fields req_change
)
286 const char* logon_scripts
[] = { "start_login.cmd", "login.bat", "start.cmd" };
287 const char* home_dirs
[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
288 const char* home_drives
[] = { "H:", "z:", "I:", "J:", "n:" };
289 const uint32_t flags
[] = { (ACB_DISABLED
| ACB_NORMAL
| ACB_PW_EXPIRED
),
290 (ACB_NORMAL
| ACB_PWNOEXP
),
291 (ACB_NORMAL
| ACB_PW_EXPIRED
) };
292 const char *homedir
, *homedrive
, *logonscript
;
296 torture_comment(tctx
, "Fields to change: [");
298 for (i
= 0; i
< num_changes
&& i
<= USER_FIELD_LAST
; i
++) {
301 testfld
= (req_change
== none
) ? (random() % USER_FIELD_LAST
) + 1 : req_change
;
303 /* get one in case we hit time field this time */
304 gettimeofday(&now
, NULL
);
308 continue_if_field_set(r
->in
.account_name
);
309 r
->in
.account_name
= talloc_asprintf(mem_ctx
, TEST_CHG_ACCOUNTNAME
,
310 (int)(random() % 100));
311 fldname
= "account_name";
313 /* update the test's user name in case it's about to change */
314 *user_name
= talloc_strdup(mem_ctx
, r
->in
.account_name
);
318 continue_if_field_set(r
->in
.full_name
);
319 r
->in
.full_name
= talloc_asprintf(mem_ctx
, TEST_CHG_FULLNAME
,
320 (unsigned int)random(), (unsigned int)random());
321 fldname
= "full_name";
324 case acct_description
:
325 continue_if_field_set(r
->in
.description
);
326 r
->in
.description
= talloc_asprintf(mem_ctx
, TEST_CHG_DESCRIPTION
,
328 fldname
= "description";
331 case acct_home_directory
:
332 continue_if_field_set(r
->in
.home_directory
);
333 homedir
= home_dirs
[random() % ARRAY_SIZE(home_dirs
)];
334 r
->in
.home_directory
= talloc_strdup(mem_ctx
, homedir
);
335 fldname
= "home_dir";
338 case acct_home_drive
:
339 continue_if_field_set(r
->in
.home_drive
);
340 homedrive
= home_drives
[random() % ARRAY_SIZE(home_drives
)];
341 r
->in
.home_drive
= talloc_strdup(mem_ctx
, homedrive
);
342 fldname
= "home_drive";
346 continue_if_field_set(r
->in
.comment
);
347 r
->in
.comment
= talloc_asprintf(mem_ctx
, TEST_CHG_COMMENT
,
348 (unsigned long)random(), (unsigned long)random());
352 case acct_logon_script
:
353 continue_if_field_set(r
->in
.logon_script
);
354 logonscript
= logon_scripts
[random() % ARRAY_SIZE(logon_scripts
)];
355 r
->in
.logon_script
= talloc_strdup(mem_ctx
, logonscript
);
356 fldname
= "logon_script";
359 case acct_profile_path
:
360 continue_if_field_set(r
->in
.profile_path
);
361 r
->in
.profile_path
= talloc_asprintf(mem_ctx
, TEST_CHG_PROFILEPATH
,
362 (unsigned long)random(), (unsigned int)random());
363 fldname
= "profile_path";
367 continue_if_field_set(r
->in
.acct_expiry
);
368 now
= timeval_add(&now
, (random() % (31*24*60*60)), 0);
369 r
->in
.acct_expiry
= (struct timeval
*)talloc_memdup(mem_ctx
, &now
, sizeof(now
));
370 fldname
= "acct_expiry";
374 continue_if_field_set(r
->in
.acct_flags
);
375 r
->in
.acct_flags
= flags
[random() % ARRAY_SIZE(flags
)];
376 fldname
= "acct_flags";
380 fldname
= "unknown_field";
383 torture_comment(tctx
, ((i
< num_changes
- 1) ? "%s," : "%s"), fldname
);
385 /* disable requested field (it's supposed to be the only one used) */
386 if (req_change
!= none
) req_change
= none
;
389 torture_comment(tctx
, "]\n");
393 #define TEST_STR_FLD(fld) \
394 if (!strequal(req.in.fld, user_req.out.fld)) { \
395 torture_comment(torture, "failed to change '%s'\n", #fld); \
400 #define TEST_TIME_FLD(fld) \
401 if (timeval_compare(req.in.fld, user_req.out.fld)) { \
402 torture_comment(torture, "failed to change '%s'\n", #fld); \
407 #define TEST_NUM_FLD(fld) \
408 if (req.in.fld != user_req.out.fld) { \
409 torture_comment(torture, "failed to change '%s'\n", #fld); \
415 static bool _libnet_context_init_pipes(struct torture_context
*tctx
,
416 struct libnet_context
*libnet_ctx
)
420 /* connect SAMR pipe */
421 status
= torture_rpc_connection(tctx
,
422 &libnet_ctx
->samr
.pipe
,
424 torture_assert_ntstatus_ok(tctx
, status
, "Failed to open SAMR pipe");
426 libnet_ctx
->samr
.samr_handle
= libnet_ctx
->samr
.pipe
->binding_handle
;
429 /* connect LSARPC pipe */
430 status
= torture_rpc_connection(tctx
,
431 &libnet_ctx
->lsa
.pipe
,
433 torture_assert_ntstatus_ok(tctx
, status
, "Failed to open LSA pipe");
435 libnet_ctx
->lsa
.lsa_handle
= libnet_ctx
->lsa
.pipe
->binding_handle
;
440 bool torture_modifyuser(struct torture_context
*torture
)
443 struct dcerpc_pipe
*p
;
444 TALLOC_CTX
*prep_mem_ctx
;
445 struct policy_handle h
;
446 struct lsa_String domain_name
;
448 struct libnet_context
*ctx
;
449 struct libnet_ModifyUser req
;
450 struct libnet_UserInfo user_req
;
453 struct dcerpc_binding_handle
*b
;
455 prep_mem_ctx
= talloc_init("prepare test_deleteuser");
457 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
458 ctx
->cred
= cmdline_credentials
;
460 status
= torture_rpc_connection(torture
,
463 if (!NT_STATUS_IS_OK(status
)) {
467 b
= p
->binding_handle
;
469 name
= talloc_strdup(prep_mem_ctx
, TEST_USERNAME
);
471 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
472 if (!test_domain_open(torture
, b
, &domain_name
, prep_mem_ctx
, &h
, NULL
)) {
477 if (!test_user_create(torture
, b
, prep_mem_ctx
, &h
, name
, NULL
)) {
482 torture_comment(torture
, "Testing change of all fields - each single one in turn\n");
484 if (!_libnet_context_init_pipes(torture
, ctx
)) {
488 for (fld
= USER_FIELD_FIRST
; fld
<= USER_FIELD_LAST
; fld
++) {
490 req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
491 req
.in
.user_name
= name
;
493 set_test_changes(torture
, torture
, &req
, 1, &name
, fld
);
495 status
= libnet_ModifyUser(ctx
, torture
, &req
);
496 if (!NT_STATUS_IS_OK(status
)) {
497 torture_comment(torture
, "libnet_ModifyUser call failed: %s\n", nt_errstr(status
));
502 ZERO_STRUCT(user_req
);
503 user_req
.in
.domain_name
= lp_workgroup(torture
->lp_ctx
);
504 user_req
.in
.data
.user_name
= name
;
505 user_req
.in
.level
= USER_INFO_BY_NAME
;
507 status
= libnet_UserInfo(ctx
, torture
, &user_req
);
508 if (!NT_STATUS_IS_OK(status
)) {
509 torture_comment(torture
, "libnet_UserInfo call failed: %s\n", nt_errstr(status
));
515 case acct_name
: TEST_STR_FLD(account_name
);
517 case acct_full_name
: TEST_STR_FLD(full_name
);
519 case acct_comment
: TEST_STR_FLD(comment
);
521 case acct_description
: TEST_STR_FLD(description
);
523 case acct_home_directory
: TEST_STR_FLD(home_directory
);
525 case acct_home_drive
: TEST_STR_FLD(home_drive
);
527 case acct_logon_script
: TEST_STR_FLD(logon_script
);
529 case acct_profile_path
: TEST_STR_FLD(profile_path
);
531 case acct_expiry
: TEST_TIME_FLD(acct_expiry
);
533 case acct_flags
: TEST_NUM_FLD(acct_flags
);
541 if (!test_cleanup(torture
, ctx
->samr
.pipe
->binding_handle
,
542 torture
, &ctx
->samr
.handle
, TEST_USERNAME
)) {
543 torture_comment(torture
, "cleanup failed\n");
548 if (!test_samr_close_handle(torture
,
549 ctx
->samr
.pipe
->binding_handle
, torture
, &ctx
->samr
.handle
)) {
550 torture_comment(torture
, "domain close failed\n");
556 talloc_free(prep_mem_ctx
);
561 bool torture_userinfo_api(struct torture_context
*torture
)
563 const char *name
= TEST_USERNAME
;
566 TALLOC_CTX
*mem_ctx
= NULL
, *prep_mem_ctx
;
567 struct libnet_context
*ctx
;
568 struct dcerpc_pipe
*p
;
569 struct policy_handle h
;
570 struct lsa_String domain_name
;
571 struct libnet_UserInfo req
;
572 struct dcerpc_binding_handle
*b
;
574 prep_mem_ctx
= talloc_init("prepare torture user info");
576 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
577 ctx
->cred
= cmdline_credentials
;
579 status
= torture_rpc_connection(torture
,
582 if (!NT_STATUS_IS_OK(status
)) {
585 b
= p
->binding_handle
;
587 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
588 if (!test_domain_open(torture
, b
, &domain_name
, prep_mem_ctx
, &h
, NULL
)) {
593 if (!test_user_create(torture
, b
, prep_mem_ctx
, &h
, name
, NULL
)) {
598 mem_ctx
= talloc_init("torture user info");
602 req
.in
.domain_name
= domain_name
.string
;
603 req
.in
.data
.user_name
= name
;
604 req
.in
.level
= USER_INFO_BY_NAME
;
606 status
= libnet_UserInfo(ctx
, mem_ctx
, &req
);
607 if (!NT_STATUS_IS_OK(status
)) {
608 torture_comment(torture
, "libnet_UserInfo call failed: %s\n", nt_errstr(status
));
613 if (!test_cleanup(torture
, ctx
->samr
.pipe
->binding_handle
, mem_ctx
, &ctx
->samr
.handle
, TEST_USERNAME
)) {
614 torture_comment(torture
, "cleanup failed\n");
619 if (!test_samr_close_handle(torture
,
620 ctx
->samr
.pipe
->binding_handle
, mem_ctx
, &ctx
->samr
.handle
)) {
621 torture_comment(torture
, "domain close failed\n");
628 talloc_free(mem_ctx
);
633 bool torture_userlist(struct torture_context
*torture
)
637 TALLOC_CTX
*mem_ctx
= NULL
;
638 struct libnet_context
*ctx
;
639 struct lsa_String domain_name
;
640 struct libnet_UserList req
;
643 ctx
= libnet_context_init(torture
->ev
, torture
->lp_ctx
);
644 ctx
->cred
= cmdline_credentials
;
646 domain_name
.string
= lp_workgroup(torture
->lp_ctx
);
647 mem_ctx
= talloc_init("torture user list");
651 torture_comment(torture
, "listing user accounts:\n");
655 req
.in
.domain_name
= domain_name
.string
;
656 req
.in
.page_size
= 128;
657 req
.in
.resume_index
= req
.out
.resume_index
;
659 status
= libnet_UserList(ctx
, mem_ctx
, &req
);
660 if (!NT_STATUS_IS_OK(status
) &&
661 !NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) break;
663 for (i
= 0; i
< req
.out
.count
; i
++) {
664 torture_comment(torture
, "\tuser: %s, sid=%s\n",
665 req
.out
.users
[i
].username
, req
.out
.users
[i
].sid
);
668 } while (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
));
670 if (!(NT_STATUS_IS_OK(status
) ||
671 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
))) {
672 torture_comment(torture
, "libnet_UserList call failed: %s\n", nt_errstr(status
));
677 if (!test_samr_close_handle(torture
,
678 ctx
->samr
.pipe
->binding_handle
, mem_ctx
, &ctx
->samr
.handle
)) {
679 torture_comment(torture
, "samr domain close failed\n");
684 if (!test_lsa_close(torture
, ctx
->lsa
.pipe
->binding_handle
, mem_ctx
, &ctx
->lsa
.handle
)) {
685 torture_comment(torture
, "lsa domain close failed\n");
692 talloc_free(mem_ctx
);