Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : utility code to join/leave a domain
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : /*
23 : this code is used by other torture modules to join/leave a domain
24 : as either a member, bdc or thru a trust relationship
25 : */
26 :
27 : #include "includes.h"
28 : #include "system/time.h"
29 : #include "libnet/libnet.h"
30 : #include "lib/cmdline/cmdline.h"
31 : #include "librpc/gen_ndr/ndr_lsa_c.h"
32 : #include "librpc/gen_ndr/ndr_samr_c.h"
33 :
34 : #include "libcli/auth/libcli_auth.h"
35 : #include "torture/rpc/torture_rpc.h"
36 : #include "libcli/security/security.h"
37 : #include "param/param.h"
38 : #include "source3/rpc_client/init_samr.h"
39 :
40 : struct test_join {
41 : struct dcerpc_pipe *p;
42 : struct policy_handle user_handle;
43 : struct policy_handle domain_handle;
44 : struct libnet_JoinDomain *libnet_r;
45 : struct dom_sid *dom_sid;
46 : const char *dom_netbios_name;
47 : const char *dom_dns_name;
48 : struct dom_sid *user_sid;
49 : struct GUID user_guid;
50 : const char *netbios_name;
51 : };
52 :
53 :
54 11 : static NTSTATUS DeleteUser_byname(struct torture_context *tctx,
55 : struct dcerpc_binding_handle *b,
56 : TALLOC_CTX *mem_ctx,
57 : struct policy_handle *handle, const char *name)
58 : {
59 0 : NTSTATUS status;
60 0 : struct samr_DeleteUser d;
61 0 : struct policy_handle user_handle;
62 0 : uint32_t rid;
63 0 : struct samr_LookupNames n;
64 0 : struct samr_Ids rids, types;
65 0 : struct lsa_String sname;
66 0 : struct samr_OpenUser r;
67 :
68 11 : sname.string = name;
69 :
70 11 : n.in.domain_handle = handle;
71 11 : n.in.num_names = 1;
72 11 : n.in.names = &sname;
73 11 : n.out.rids = &rids;
74 11 : n.out.types = &types;
75 :
76 11 : status = dcerpc_samr_LookupNames_r(b, mem_ctx, &n);
77 11 : if (!NT_STATUS_IS_OK(status)) {
78 0 : return status;
79 : }
80 11 : if (NT_STATUS_IS_OK(n.out.result)) {
81 11 : rid = n.out.rids->ids[0];
82 : } else {
83 0 : return n.out.result;
84 : }
85 :
86 11 : r.in.domain_handle = handle;
87 11 : r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
88 11 : r.in.rid = rid;
89 11 : r.out.user_handle = &user_handle;
90 :
91 11 : status = dcerpc_samr_OpenUser_r(b, mem_ctx, &r);
92 11 : if (!NT_STATUS_IS_OK(status)) {
93 0 : torture_comment(tctx, "OpenUser(%s) failed - %s\n", name, nt_errstr(status));
94 0 : return status;
95 : }
96 11 : if (!NT_STATUS_IS_OK(r.out.result)) {
97 0 : torture_comment(tctx, "OpenUser(%s) failed - %s\n", name, nt_errstr(r.out.result));
98 0 : return r.out.result;
99 : }
100 :
101 11 : d.in.user_handle = &user_handle;
102 11 : d.out.user_handle = &user_handle;
103 11 : status = dcerpc_samr_DeleteUser_r(b, mem_ctx, &d);
104 11 : if (!NT_STATUS_IS_OK(status)) {
105 0 : return status;
106 : }
107 11 : if (!NT_STATUS_IS_OK(d.out.result)) {
108 0 : return d.out.result;
109 : }
110 :
111 11 : return NT_STATUS_OK;
112 : }
113 :
114 : /*
115 : create a test user in the domain
116 : an opaque pointer is returned. Pass it to torture_leave_domain()
117 : when finished
118 : */
119 :
120 29 : struct test_join *torture_create_testuser_max_pwlen(struct torture_context *tctx,
121 : const char *username,
122 : const char *domain,
123 : uint16_t acct_type,
124 : const char **random_password,
125 : int max_pw_len)
126 : {
127 0 : NTSTATUS status;
128 0 : struct samr_Connect c;
129 0 : struct samr_CreateUser2 r;
130 0 : struct samr_OpenDomain o;
131 0 : struct samr_LookupDomain l;
132 29 : struct dom_sid2 *sid = NULL;
133 0 : struct samr_GetUserPwInfo pwp;
134 0 : struct samr_PwInfo info;
135 0 : struct samr_SetUserInfo s;
136 0 : union samr_UserInfo u;
137 0 : struct policy_handle handle;
138 0 : uint32_t access_granted;
139 0 : uint32_t rid;
140 0 : DATA_BLOB session_key;
141 0 : struct lsa_String name;
142 :
143 29 : int policy_min_pw_len = 0;
144 0 : struct test_join *join;
145 0 : char *random_pw;
146 29 : const char *dc_binding = torture_setting_string(tctx, "dc_binding", NULL);
147 29 : struct dcerpc_binding_handle *b = NULL;
148 29 : join = talloc(NULL, struct test_join);
149 29 : if (join == NULL) {
150 0 : return NULL;
151 : }
152 :
153 29 : ZERO_STRUCTP(join);
154 :
155 29 : torture_comment(tctx, "Connecting to SAMR\n");
156 :
157 29 : if (dc_binding) {
158 0 : status = dcerpc_pipe_connect(join,
159 : &join->p,
160 : dc_binding,
161 : &ndr_table_samr,
162 : samba_cmdline_get_creds(),
163 : NULL, tctx->lp_ctx);
164 :
165 : } else {
166 29 : status = torture_rpc_connection(tctx,
167 : &join->p,
168 : &ndr_table_samr);
169 : }
170 29 : if (!NT_STATUS_IS_OK(status)) {
171 0 : return NULL;
172 : }
173 29 : b = join->p->binding_handle;
174 :
175 29 : c.in.system_name = NULL;
176 29 : c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
177 29 : c.out.connect_handle = &handle;
178 :
179 29 : status = dcerpc_samr_Connect_r(b, join, &c);
180 29 : if (!NT_STATUS_IS_OK(status)) {
181 0 : const char *errstr = nt_errstr(status);
182 0 : torture_comment(tctx, "samr_Connect failed - %s\n", errstr);
183 0 : return NULL;
184 : }
185 29 : if (!NT_STATUS_IS_OK(c.out.result)) {
186 0 : const char *errstr = nt_errstr(c.out.result);
187 0 : torture_comment(tctx, "samr_Connect failed - %s\n", errstr);
188 0 : return NULL;
189 : }
190 :
191 29 : if (domain) {
192 13 : torture_comment(tctx, "Opening domain %s\n", domain);
193 :
194 13 : name.string = domain;
195 13 : l.in.connect_handle = &handle;
196 13 : l.in.domain_name = &name;
197 13 : l.out.sid = &sid;
198 :
199 13 : status = dcerpc_samr_LookupDomain_r(b, join, &l);
200 13 : if (!NT_STATUS_IS_OK(status)) {
201 0 : torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(status));
202 0 : goto failed;
203 : }
204 13 : if (!NT_STATUS_IS_OK(l.out.result)) {
205 0 : torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(l.out.result));
206 0 : goto failed;
207 : }
208 : } else {
209 0 : struct samr_EnumDomains e;
210 16 : uint32_t resume_handle = 0, num_entries;
211 0 : struct samr_SamArray *sam;
212 0 : int i;
213 :
214 16 : e.in.connect_handle = &handle;
215 16 : e.in.buf_size = (uint32_t)-1;
216 16 : e.in.resume_handle = &resume_handle;
217 16 : e.out.sam = &sam;
218 16 : e.out.num_entries = &num_entries;
219 16 : e.out.resume_handle = &resume_handle;
220 :
221 16 : status = dcerpc_samr_EnumDomains_r(b, join, &e);
222 16 : if (!NT_STATUS_IS_OK(status)) {
223 0 : torture_comment(tctx, "EnumDomains failed - %s\n", nt_errstr(status));
224 0 : goto failed;
225 : }
226 16 : if (!NT_STATUS_IS_OK(e.out.result)) {
227 0 : torture_comment(tctx, "EnumDomains failed - %s\n", nt_errstr(e.out.result));
228 0 : goto failed;
229 : }
230 16 : if ((num_entries != 2) || (sam && sam->count != 2)) {
231 0 : torture_comment(tctx, "unexpected number of domains\n");
232 0 : goto failed;
233 : }
234 16 : for (i=0; i < 2; i++) {
235 16 : if (!strequal(sam->entries[i].name.string, "builtin")) {
236 16 : domain = sam->entries[i].name.string;
237 16 : break;
238 : }
239 : }
240 16 : if (domain) {
241 16 : torture_comment(tctx, "Opening domain %s\n", domain);
242 :
243 16 : name.string = domain;
244 16 : l.in.connect_handle = &handle;
245 16 : l.in.domain_name = &name;
246 16 : l.out.sid = &sid;
247 :
248 16 : status = dcerpc_samr_LookupDomain_r(b, join, &l);
249 16 : if (!NT_STATUS_IS_OK(status)) {
250 0 : torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(status));
251 0 : goto failed;
252 : }
253 16 : if (!NT_STATUS_IS_OK(l.out.result)) {
254 0 : torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(l.out.result));
255 0 : goto failed;
256 : }
257 : } else {
258 0 : torture_comment(tctx, "cannot proceed without domain name\n");
259 0 : goto failed;
260 : }
261 : }
262 :
263 29 : talloc_steal(join, *l.out.sid);
264 29 : join->dom_sid = *l.out.sid;
265 29 : join->dom_netbios_name = talloc_strdup(join, domain);
266 29 : if (!join->dom_netbios_name) goto failed;
267 :
268 29 : o.in.connect_handle = &handle;
269 29 : o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
270 29 : o.in.sid = *l.out.sid;
271 29 : o.out.domain_handle = &join->domain_handle;
272 :
273 29 : status = dcerpc_samr_OpenDomain_r(b, join, &o);
274 29 : if (!NT_STATUS_IS_OK(status)) {
275 0 : torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(status));
276 0 : goto failed;
277 : }
278 29 : if (!NT_STATUS_IS_OK(o.out.result)) {
279 0 : torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(o.out.result));
280 0 : goto failed;
281 : }
282 :
283 29 : torture_comment(tctx, "Creating account %s\n", username);
284 :
285 31 : again:
286 31 : name.string = username;
287 31 : r.in.domain_handle = &join->domain_handle;
288 31 : r.in.account_name = &name;
289 31 : r.in.acct_flags = acct_type;
290 31 : r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
291 31 : r.out.user_handle = &join->user_handle;
292 31 : r.out.access_granted = &access_granted;
293 31 : r.out.rid = &rid;
294 :
295 31 : status = dcerpc_samr_CreateUser2_r(b, join, &r);
296 31 : if (!NT_STATUS_IS_OK(status)) {
297 0 : torture_comment(tctx, "CreateUser2 failed - %s\n", nt_errstr(status));
298 0 : goto failed;
299 : }
300 :
301 31 : if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
302 2 : status = DeleteUser_byname(tctx, b, join, &join->domain_handle, name.string);
303 2 : if (NT_STATUS_IS_OK(status)) {
304 2 : goto again;
305 : }
306 : }
307 :
308 29 : if (!NT_STATUS_IS_OK(r.out.result)) {
309 0 : torture_comment(tctx, "CreateUser2 failed - %s\n", nt_errstr(r.out.result));
310 0 : goto failed;
311 : }
312 :
313 29 : join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid);
314 :
315 29 : pwp.in.user_handle = &join->user_handle;
316 29 : pwp.out.info = &info;
317 :
318 29 : status = dcerpc_samr_GetUserPwInfo_r(b, join, &pwp);
319 29 : if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(pwp.out.result)) {
320 29 : policy_min_pw_len = pwp.out.info->min_password_length;
321 : }
322 :
323 29 : random_pw = generate_random_password(join, MAX(8, policy_min_pw_len), max_pw_len);
324 :
325 29 : torture_comment(tctx, "Setting account password '%s'\n", random_pw);
326 :
327 29 : ZERO_STRUCT(u);
328 29 : s.in.user_handle = &join->user_handle;
329 29 : s.in.info = &u;
330 29 : s.in.level = 24;
331 :
332 29 : u.info24.password_expired = 0;
333 :
334 29 : status = dcerpc_fetch_session_key(join->p, &session_key);
335 29 : if (!NT_STATUS_IS_OK(status)) {
336 0 : torture_comment(tctx, "SetUserInfo level %u - no session key - %s\n",
337 0 : s.in.level, nt_errstr(status));
338 0 : torture_leave_domain(tctx, join);
339 0 : goto failed;
340 : }
341 :
342 29 : status = init_samr_CryptPassword(random_pw,
343 : &session_key,
344 : &u.info24.password);
345 29 : torture_assert_ntstatus_ok(tctx,
346 : status,
347 : "init_samr_CryptPassword failed");
348 :
349 29 : status = dcerpc_samr_SetUserInfo_r(b, join, &s);
350 29 : if (!NT_STATUS_IS_OK(status)) {
351 0 : torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(status));
352 0 : goto failed;
353 : }
354 29 : if (!NT_STATUS_IS_OK(s.out.result)) {
355 0 : torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(s.out.result));
356 0 : goto failed;
357 : }
358 :
359 29 : ZERO_STRUCT(u);
360 29 : s.in.user_handle = &join->user_handle;
361 29 : s.in.info = &u;
362 29 : s.in.level = 21;
363 :
364 29 : u.info21.acct_flags = acct_type | ACB_PWNOEXP;
365 29 : u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
366 :
367 29 : u.info21.comment.string = talloc_asprintf(join,
368 : "Tortured by Samba4: %s",
369 : timestring(join, time(NULL)));
370 :
371 29 : u.info21.full_name.string = talloc_asprintf(join,
372 : "Torture account for Samba4: %s",
373 : timestring(join, time(NULL)));
374 :
375 29 : u.info21.description.string = talloc_asprintf(join,
376 : "Samba4 torture account created by host %s: %s",
377 : lpcfg_netbios_name(tctx->lp_ctx),
378 : timestring(join, time(NULL)));
379 :
380 29 : torture_comment(tctx, "Resetting ACB flags, force pw change time\n");
381 :
382 29 : status = dcerpc_samr_SetUserInfo_r(b, join, &s);
383 29 : if (!NT_STATUS_IS_OK(status)) {
384 0 : torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(status));
385 0 : goto failed;
386 : }
387 29 : if (!NT_STATUS_IS_OK(s.out.result)) {
388 0 : torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(s.out.result));
389 0 : goto failed;
390 : }
391 :
392 29 : if (random_password) {
393 29 : *random_password = random_pw;
394 : }
395 :
396 29 : return join;
397 :
398 0 : failed:
399 0 : torture_leave_domain(tctx, join);
400 0 : return NULL;
401 : }
402 :
403 : /*
404 : * Set privileges on an account.
405 : */
406 :
407 4 : static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
408 : {
409 4 : name->string = s;
410 4 : }
411 4 : static void init_lsa_String(struct lsa_String *name, const char *s)
412 : {
413 4 : name->string = s;
414 4 : }
415 :
416 4 : bool torture_setup_privs(struct torture_context *tctx,
417 : struct dcerpc_pipe *p,
418 : uint32_t num_privs,
419 : const char **privs,
420 : const struct dom_sid *user_sid)
421 : {
422 4 : struct dcerpc_binding_handle *b = p->binding_handle;
423 0 : struct policy_handle *handle;
424 0 : int i;
425 :
426 4 : torture_assert(tctx,
427 : test_lsa_OpenPolicy2(b, tctx, &handle),
428 : "failed to open policy");
429 :
430 8 : for (i=0; i < num_privs; i++) {
431 0 : struct lsa_LookupPrivValue r;
432 0 : struct lsa_LUID luid;
433 0 : struct lsa_String name;
434 :
435 4 : init_lsa_String(&name, privs[i]);
436 :
437 4 : r.in.handle = handle;
438 4 : r.in.name = &name;
439 4 : r.out.luid = &luid;
440 :
441 4 : torture_assert_ntstatus_ok(tctx,
442 : dcerpc_lsa_LookupPrivValue_r(b, tctx, &r),
443 : "lsa_LookupPrivValue failed");
444 4 : if (!NT_STATUS_IS_OK(r.out.result)) {
445 0 : torture_comment(tctx, "lsa_LookupPrivValue failed for '%s' with %s\n",
446 0 : privs[i], nt_errstr(r.out.result));
447 0 : return false;
448 : }
449 : }
450 :
451 : {
452 0 : struct lsa_AddAccountRights r;
453 0 : struct lsa_RightSet rights;
454 :
455 4 : rights.count = num_privs;
456 4 : rights.names = talloc_zero_array(tctx, struct lsa_StringLarge, rights.count);
457 8 : for (i=0; i < rights.count; i++) {
458 4 : init_lsa_StringLarge(&rights.names[i], privs[i]);
459 : }
460 :
461 4 : r.in.handle = handle;
462 4 : r.in.sid = discard_const_p(struct dom_sid, user_sid);
463 4 : r.in.rights = &rights;
464 :
465 4 : torture_assert_ntstatus_ok(tctx,
466 : dcerpc_lsa_AddAccountRights_r(b, tctx, &r),
467 : "lsa_AddAccountRights failed");
468 4 : torture_assert_ntstatus_ok(tctx, r.out.result,
469 : "lsa_AddAccountRights failed");
470 : }
471 :
472 4 : test_lsa_Close(b, tctx, handle);
473 :
474 4 : return true;
475 : }
476 :
477 17 : struct test_join *torture_create_testuser(struct torture_context *torture,
478 : const char *username,
479 : const char *domain,
480 : uint16_t acct_type,
481 : const char **random_password)
482 : {
483 17 : return torture_create_testuser_max_pwlen(torture, username, domain, acct_type, random_password, 255);
484 : }
485 :
486 9 : NTSTATUS torture_delete_testuser(struct torture_context *torture,
487 : struct test_join *join,
488 : const char *username)
489 : {
490 0 : NTSTATUS status;
491 :
492 9 : status = DeleteUser_byname(torture,
493 9 : join->p->binding_handle,
494 : torture,
495 : &join->domain_handle,
496 : username);
497 :
498 9 : return status;
499 : }
500 :
501 546 : _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx,
502 : const char *machine_name,
503 : uint32_t acct_flags,
504 : struct cli_credentials **machine_credentials)
505 : {
506 72 : NTSTATUS status;
507 72 : struct libnet_context *libnet_ctx;
508 72 : struct libnet_JoinDomain *libnet_r;
509 72 : struct test_join *tj;
510 72 : struct samr_SetUserInfo s;
511 72 : union samr_UserInfo u;
512 546 : const char *binding_str = NULL;
513 546 : struct dcerpc_binding *binding = NULL;
514 72 : enum dcerpc_transport_t transport;
515 :
516 546 : tj = talloc_zero(tctx, struct test_join);
517 546 : if (!tj) return NULL;
518 :
519 546 : binding_str = torture_setting_string(tctx, "binding", NULL);
520 546 : if (binding_str == NULL) {
521 0 : const char *host = torture_setting_string(tctx, "host", NULL);
522 0 : binding_str = talloc_asprintf(tj, "ncacn_np:%s", host);
523 : }
524 546 : status = dcerpc_parse_binding(tj, binding_str, &binding);
525 546 : if (!NT_STATUS_IS_OK(status)) {
526 0 : DEBUG(0, ("dcerpc_parse_binding(%s) failed - %s\n",
527 : binding_str, nt_errstr(status)));
528 0 : talloc_free(tj);
529 0 : return NULL;
530 : }
531 546 : transport = dcerpc_binding_get_transport(binding);
532 546 : switch (transport) {
533 60 : case NCALRPC:
534 : case NCACN_UNIX_STREAM:
535 60 : break;
536 486 : default:
537 486 : dcerpc_binding_set_transport(binding, NCACN_NP);
538 486 : dcerpc_binding_set_flags(binding, 0, DCERPC_AUTH_OPTIONS);
539 486 : break;
540 : }
541 :
542 546 : libnet_r = talloc_zero(tj, struct libnet_JoinDomain);
543 546 : if (!libnet_r) {
544 0 : talloc_free(tj);
545 0 : return NULL;
546 : }
547 :
548 546 : libnet_ctx = libnet_context_init(tctx->ev, tctx->lp_ctx);
549 546 : if (!libnet_ctx) {
550 0 : talloc_free(tj);
551 0 : return NULL;
552 : }
553 :
554 546 : tj->libnet_r = libnet_r;
555 :
556 546 : libnet_ctx->cred = samba_cmdline_get_creds();
557 546 : libnet_r->in.binding = dcerpc_binding_string(libnet_r, binding);
558 546 : if (libnet_r->in.binding == NULL) {
559 0 : talloc_free(tj);
560 0 : return NULL;
561 : }
562 546 : libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED;
563 546 : libnet_r->in.netbios_name = machine_name;
564 546 : libnet_r->in.account_name = talloc_asprintf(libnet_r, "%s$", machine_name);
565 546 : if (!libnet_r->in.account_name) {
566 0 : talloc_free(tj);
567 0 : return NULL;
568 : }
569 :
570 546 : libnet_r->in.acct_type = acct_flags;
571 546 : libnet_r->in.recreate_account = true;
572 :
573 546 : status = libnet_JoinDomain(libnet_ctx, libnet_r, libnet_r);
574 546 : if (!NT_STATUS_IS_OK(status)) {
575 0 : if (libnet_r->out.error_string) {
576 0 : DEBUG(0, ("Domain join failed - %s\n", libnet_r->out.error_string));
577 : } else {
578 0 : DEBUG(0, ("Domain join failed - %s\n", nt_errstr(status)));
579 : }
580 0 : talloc_free(tj);
581 0 : return NULL;
582 : }
583 546 : tj->p = libnet_r->out.samr_pipe;
584 546 : tj->user_handle = *libnet_r->out.user_handle;
585 546 : tj->dom_sid = libnet_r->out.domain_sid;
586 546 : talloc_steal(tj, libnet_r->out.domain_sid);
587 546 : tj->dom_netbios_name = libnet_r->out.domain_name;
588 546 : talloc_steal(tj, libnet_r->out.domain_name);
589 546 : tj->dom_dns_name = libnet_r->out.realm;
590 546 : talloc_steal(tj, libnet_r->out.realm);
591 546 : tj->user_guid = libnet_r->out.account_guid;
592 546 : tj->netbios_name = talloc_strdup(tj, machine_name);
593 546 : if (!tj->netbios_name) {
594 0 : talloc_free(tj);
595 0 : return NULL;
596 : }
597 :
598 546 : ZERO_STRUCT(u);
599 546 : s.in.user_handle = &tj->user_handle;
600 546 : s.in.info = &u;
601 546 : s.in.level = 21;
602 :
603 546 : u.info21.fields_present = SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
604 546 : u.info21.comment.string = talloc_asprintf(tj,
605 : "Tortured by Samba4: %s",
606 : timestring(tj, time(NULL)));
607 546 : u.info21.full_name.string = talloc_asprintf(tj,
608 : "Torture account for Samba4: %s",
609 : timestring(tj, time(NULL)));
610 :
611 546 : u.info21.description.string = talloc_asprintf(tj,
612 : "Samba4 torture account created by host %s: %s",
613 : lpcfg_netbios_name(tctx->lp_ctx), timestring(tj, time(NULL)));
614 :
615 546 : status = dcerpc_samr_SetUserInfo_r(tj->p->binding_handle, tj, &s);
616 546 : if (!NT_STATUS_IS_OK(status)) {
617 0 : torture_comment(tctx, "SetUserInfo (non-critical) failed - %s\n", nt_errstr(status));
618 : }
619 546 : if (!NT_STATUS_IS_OK(s.out.result)) {
620 0 : torture_comment(tctx, "SetUserInfo (non-critical) failed - %s\n", nt_errstr(s.out.result));
621 : }
622 :
623 546 : *machine_credentials = cli_credentials_init(tj);
624 546 : cli_credentials_set_conf(*machine_credentials, tctx->lp_ctx);
625 546 : cli_credentials_set_workstation(*machine_credentials, machine_name, CRED_SPECIFIED);
626 546 : cli_credentials_set_domain(*machine_credentials, libnet_r->out.domain_name, CRED_SPECIFIED);
627 546 : if (libnet_r->out.realm) {
628 496 : cli_credentials_set_realm(*machine_credentials, libnet_r->out.realm, CRED_SPECIFIED);
629 : }
630 546 : cli_credentials_set_username(*machine_credentials, libnet_r->in.account_name, CRED_SPECIFIED);
631 546 : cli_credentials_set_password(*machine_credentials, libnet_r->out.join_password, CRED_SPECIFIED);
632 546 : cli_credentials_set_kvno(*machine_credentials, libnet_r->out.kvno);
633 546 : if (acct_flags & ACB_SVRTRUST) {
634 265 : cli_credentials_set_secure_channel_type(*machine_credentials,
635 : SEC_CHAN_BDC);
636 281 : } else if (acct_flags & ACB_WSTRUST) {
637 281 : cli_credentials_set_secure_channel_type(*machine_credentials,
638 : SEC_CHAN_WKSTA);
639 : } else {
640 0 : DEBUG(0, ("Invalid account type specified to torture_join_domain\n"));
641 0 : talloc_free(*machine_credentials);
642 0 : return NULL;
643 : }
644 :
645 474 : return tj;
646 : }
647 :
648 13 : struct dcerpc_pipe *torture_join_samr_pipe(struct test_join *join)
649 : {
650 13 : return join->p;
651 : }
652 :
653 12 : struct policy_handle *torture_join_samr_user_policy(struct test_join *join)
654 : {
655 12 : return &join->user_handle;
656 : }
657 :
658 546 : static NTSTATUS torture_leave_ads_domain(struct torture_context *torture,
659 : TALLOC_CTX *mem_ctx,
660 : struct libnet_JoinDomain *libnet_r)
661 : {
662 72 : int rtn;
663 72 : TALLOC_CTX *tmp_ctx;
664 :
665 72 : struct ldb_dn *server_dn;
666 72 : struct ldb_context *ldb_ctx;
667 :
668 72 : char *remote_ldb_url;
669 :
670 : /* Check if we are a domain controller. If not, exit. */
671 546 : if (!libnet_r->out.server_dn_str) {
672 307 : return NT_STATUS_OK;
673 : }
674 :
675 239 : tmp_ctx = talloc_named(mem_ctx, 0, "torture_leave temporary context");
676 239 : if (!tmp_ctx) {
677 0 : libnet_r->out.error_string = NULL;
678 0 : return NT_STATUS_NO_MEMORY;
679 : }
680 :
681 239 : ldb_ctx = ldb_init(tmp_ctx, torture->ev);
682 239 : if (!ldb_ctx) {
683 0 : libnet_r->out.error_string = NULL;
684 0 : talloc_free(tmp_ctx);
685 0 : return NT_STATUS_NO_MEMORY;
686 : }
687 :
688 : /* Remove CN=Servers,... entry from the AD. */
689 239 : server_dn = ldb_dn_new(tmp_ctx, ldb_ctx, libnet_r->out.server_dn_str);
690 239 : if (! ldb_dn_validate(server_dn)) {
691 0 : libnet_r->out.error_string = NULL;
692 0 : talloc_free(tmp_ctx);
693 0 : return NT_STATUS_NO_MEMORY;
694 : }
695 :
696 239 : remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s",
697 : dcerpc_binding_get_string_option(libnet_r->out.samr_binding, "host"));
698 239 : if (!remote_ldb_url) {
699 0 : libnet_r->out.error_string = NULL;
700 0 : talloc_free(tmp_ctx);
701 0 : return NT_STATUS_NO_MEMORY;
702 : }
703 :
704 239 : ldb_set_opaque(ldb_ctx, "credentials", samba_cmdline_get_creds());
705 239 : ldb_set_opaque(ldb_ctx, "loadparm", samba_cmdline_get_lp_ctx());
706 :
707 239 : rtn = ldb_connect(ldb_ctx, remote_ldb_url, 0, NULL);
708 239 : if (rtn != LDB_SUCCESS) {
709 0 : libnet_r->out.error_string = NULL;
710 0 : talloc_free(tmp_ctx);
711 0 : return NT_STATUS_UNSUCCESSFUL;
712 : }
713 :
714 239 : rtn = ldb_delete(ldb_ctx, server_dn);
715 239 : if (rtn != LDB_SUCCESS) {
716 0 : libnet_r->out.error_string = NULL;
717 0 : talloc_free(tmp_ctx);
718 0 : return NT_STATUS_UNSUCCESSFUL;
719 : }
720 :
721 239 : DEBUG(0, ("%s removed successfully.\n", libnet_r->out.server_dn_str));
722 :
723 239 : talloc_free(tmp_ctx);
724 239 : return NT_STATUS_OK;
725 : }
726 :
727 : /*
728 : leave the domain, deleting the machine acct
729 : */
730 :
731 561 : _PUBLIC_ void torture_leave_domain(struct torture_context *tctx, struct test_join *join)
732 : {
733 72 : struct samr_DeleteUser d;
734 72 : NTSTATUS status;
735 :
736 561 : if (!join) {
737 0 : return;
738 : }
739 561 : d.in.user_handle = &join->user_handle;
740 561 : d.out.user_handle = &join->user_handle;
741 :
742 : /* Delete machine account */
743 561 : status = dcerpc_samr_DeleteUser_r(join->p->binding_handle, join, &d);
744 561 : if (!NT_STATUS_IS_OK(status)) {
745 0 : torture_comment(tctx, "DeleteUser failed\n");
746 561 : } else if (!NT_STATUS_IS_OK(d.out.result)) {
747 0 : torture_comment(tctx, "Delete of machine account %s failed\n",
748 : join->netbios_name);
749 : } else {
750 561 : torture_comment(tctx, "Delete of machine account %s was successful.\n",
751 : join->netbios_name);
752 : }
753 :
754 561 : if (join->libnet_r) {
755 546 : status = torture_leave_ads_domain(tctx, join, join->libnet_r);
756 : }
757 :
758 561 : talloc_free(join);
759 : }
760 :
761 : /*
762 : return the dom sid for a test join
763 : */
764 17 : _PUBLIC_ const struct dom_sid *torture_join_sid(struct test_join *join)
765 : {
766 17 : return join->dom_sid;
767 : }
768 :
769 9 : const struct dom_sid *torture_join_user_sid(struct test_join *join)
770 : {
771 9 : return join->user_sid;
772 : }
773 :
774 7 : const char *torture_join_netbios_name(struct test_join *join)
775 : {
776 7 : return join->netbios_name;
777 : }
778 :
779 4 : const struct GUID *torture_join_user_guid(struct test_join *join)
780 : {
781 4 : return &join->user_guid;
782 : }
783 :
784 16 : const char *torture_join_dom_netbios_name(struct test_join *join)
785 : {
786 16 : return join->dom_netbios_name;
787 : }
788 :
789 16 : const char *torture_join_dom_dns_name(struct test_join *join)
790 : {
791 16 : return join->dom_dns_name;
792 : }
793 :
794 : #if 0 /* Left as the documentation of the join process, but see new implementation in libnet_become_dc.c */
795 : struct test_join_ads_dc {
796 : struct test_join *join;
797 : };
798 :
799 : struct test_join_ads_dc *torture_join_domain_ads_dc(const char *machine_name,
800 : const char *domain,
801 : struct cli_credentials **machine_credentials)
802 : {
803 : struct test_join_ads_dc *join;
804 :
805 : join = talloc(NULL, struct test_join_ads_dc);
806 : if (join == NULL) {
807 : return NULL;
808 : }
809 :
810 : join->join = torture_join_domain(machine_name,
811 : ACB_SVRTRUST,
812 : machine_credentials);
813 :
814 : if (!join->join) {
815 : return NULL;
816 : }
817 :
818 : /* W2K: */
819 : /* W2K: modify userAccountControl from 4096 to 532480 */
820 :
821 : /* W2K: modify RDN to OU=Domain Controllers and skip the $ from server name */
822 :
823 : /* ask objectVersion of Schema Partition */
824 :
825 : /* ask rIDManagerReferenz of the Domain Partition */
826 :
827 : /* ask fsMORoleOwner of the RID-Manager$ object
828 : * returns CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ...
829 : */
830 :
831 : /* ask for dnsHostName of CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
832 :
833 : /* ask for objectGUID of CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
834 :
835 : /* ask for * of CN=Default-First-Site-Name, ... */
836 :
837 : /* search (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<machine_name>$)) in Domain Partition
838 : * attributes : distinguishedName, userAccountControl
839 : */
840 :
841 : /* ask * for CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
842 : * should fail with noSuchObject
843 : */
844 :
845 : /* add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
846 : *
847 : * objectClass = server
848 : * systemFlags = 50000000
849 : * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
850 : */
851 :
852 : /* ask for * of CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
853 : * should fail with noSuchObject
854 : */
855 :
856 : /* search for (ncname=<domain_nc>) in CN=Partitions,CN=Configuration,...
857 : * attributes: ncName, dnsRoot
858 : */
859 :
860 : /* modify add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
861 : * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
862 : * should fail with attributeOrValueExists
863 : */
864 :
865 : /* modify replace CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
866 : * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
867 : */
868 :
869 : /* DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
870 : *
871 : */
872 :
873 : /* replicate CN=Schema,CN=Configuration,...
874 : * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
875 : *
876 : */
877 :
878 : /* replicate CN=Configuration,...
879 : * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
880 : *
881 : */
882 :
883 : /* replicate Domain Partition
884 : * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
885 : *
886 : */
887 :
888 : /* call DsReplicaUpdateRefs() for all partitions like this:
889 : * req1: struct drsuapi_DsReplicaUpdateRefsRequest1
890 : * naming_context : *
891 : * naming_context: struct drsuapi_DsReplicaObjectIdentifier
892 : * __ndr_size : 0x000000ae (174)
893 : * __ndr_size_sid : 0x00000000 (0)
894 : * guid : 00000000-0000-0000-0000-000000000000
895 : * sid : S-0-0
896 : * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
897 : * dest_dsa_dns_name : *
898 : * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
899 : * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
900 : * options : 0x0000001c (28)
901 : * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
902 : * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
903 : * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
904 : * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
905 : * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
906 : *
907 : * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
908 : * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
909 : */
910 :
911 : /* W2K3: see libnet/libnet_become_dc.c */
912 : return join;
913 : }
914 :
915 : #endif
|