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