r8232: remove samr_String and netr_String as they are the same as lsa_String
[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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24   this code is used by other torture modules to join/leave a domain
25   as either a member, bdc or thru a trust relationship
26 */
27
28 #include "includes.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
30 #include "system/time.h"
31
32 struct test_join {
33         struct dcerpc_pipe *p;
34         struct policy_handle user_handle;
35         const char *dom_sid;
36 };
37
38
39 static NTSTATUS DeleteUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
40                                   struct policy_handle *handle, const char *name)
41 {
42         NTSTATUS status;
43         struct samr_DeleteUser d;
44         struct policy_handle user_handle;
45         uint32_t rid;
46         struct samr_LookupNames n;
47         struct lsa_String sname;
48         struct samr_OpenUser r;
49
50         sname.string = name;
51
52         n.in.domain_handle = handle;
53         n.in.num_names = 1;
54         n.in.names = &sname;
55
56         status = dcerpc_samr_LookupNames(p, mem_ctx, &n);
57         if (NT_STATUS_IS_OK(status)) {
58                 rid = n.out.rids.ids[0];
59         } else {
60                 return status;
61         }
62
63         r.in.domain_handle = handle;
64         r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
65         r.in.rid = rid;
66         r.out.user_handle = &user_handle;
67
68         status = dcerpc_samr_OpenUser(p, mem_ctx, &r);
69         if (!NT_STATUS_IS_OK(status)) {
70                 printf("OpenUser(%s) failed - %s\n", name, nt_errstr(status));
71                 return status;
72         }
73
74         d.in.user_handle = &user_handle;
75         d.out.user_handle = &user_handle;
76         status = dcerpc_samr_DeleteUser(p, mem_ctx, &d);
77         if (!NT_STATUS_IS_OK(status)) {
78                 return status;
79         }
80
81         return NT_STATUS_OK;
82 }
83
84 /*
85   create a test user in the domain
86   an opaque pointer is returned. Pass it to torture_leave_domain() 
87   when finished
88 */
89
90 struct test_join *torture_create_testuser(const char *username, 
91                                           const char *domain,
92                                           uint16_t acct_type,
93                                           const char **random_password)
94 {
95         NTSTATUS status;
96         struct samr_Connect c;
97         struct samr_CreateUser2 r;
98         struct samr_OpenDomain o;
99         struct samr_LookupDomain l;
100         struct samr_GetUserPwInfo pwp;
101         struct samr_SetUserInfo s;
102         union samr_UserInfo u;
103         struct policy_handle handle;
104         struct policy_handle domain_handle;
105         uint32_t access_granted;
106         uint32_t rid;
107         DATA_BLOB session_key;
108         struct lsa_String name;
109         struct lsa_String comment;
110         struct lsa_String full_name;
111         
112         int policy_min_pw_len = 0;
113         struct test_join *join;
114         char *random_pw;
115
116         join = talloc(NULL, struct test_join);
117         if (join == NULL) {
118                 return NULL;
119         }
120
121         ZERO_STRUCTP(join);
122
123         printf("Connecting to SAMR\n");
124
125         status = torture_rpc_connection(join, 
126                                         &join->p, 
127                                         DCERPC_SAMR_NAME,
128                                         DCERPC_SAMR_UUID,
129                                         DCERPC_SAMR_VERSION);
130         if (!NT_STATUS_IS_OK(status)) {
131                 goto failed;
132         }
133
134         c.in.system_name = NULL;
135         c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
136         c.out.connect_handle = &handle;
137
138         status = dcerpc_samr_Connect(join->p, join, &c);
139         if (!NT_STATUS_IS_OK(status)) {
140                 const char *errstr = nt_errstr(status);
141                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
142                         errstr = dcerpc_errstr(join, join->p->last_fault_code);
143                 }
144                 printf("samr_Connect failed - %s\n", errstr);
145                 goto failed;
146         }
147
148         printf("Opening domain %s\n", domain);
149
150         name.string = domain;
151         l.in.connect_handle = &handle;
152         l.in.domain_name = &name;
153
154         status = dcerpc_samr_LookupDomain(join->p, join, &l);
155         if (!NT_STATUS_IS_OK(status)) {
156                 printf("LookupDomain failed - %s\n", nt_errstr(status));
157                 goto failed;
158         }
159
160         join->dom_sid = dom_sid_string(join, l.out.sid);
161
162         o.in.connect_handle = &handle;
163         o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
164         o.in.sid = l.out.sid;
165         o.out.domain_handle = &domain_handle;
166
167         status = dcerpc_samr_OpenDomain(join->p, join, &o);
168         if (!NT_STATUS_IS_OK(status)) {
169                 printf("OpenDomain failed - %s\n", nt_errstr(status));
170                 goto failed;
171         }
172
173         printf("Creating account %s\n", username);
174
175 again:
176         name.string = username;
177         r.in.domain_handle = &domain_handle;
178         r.in.account_name = &name;
179         r.in.acct_flags = acct_type;
180         r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
181         r.out.user_handle = &join->user_handle;
182         r.out.access_granted = &access_granted;
183         r.out.rid = &rid;
184
185         status = dcerpc_samr_CreateUser2(join->p, join, &r);
186
187         if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
188                 status = DeleteUser_byname(join->p, join, &domain_handle, name.string);
189                 if (NT_STATUS_IS_OK(status)) {
190                         goto again;
191                 }
192         }
193
194         if (!NT_STATUS_IS_OK(status)) {
195                 printf("CreateUser2 failed - %s\n", nt_errstr(status));
196                 goto failed;
197         }
198
199         pwp.in.user_handle = &join->user_handle;
200
201         status = dcerpc_samr_GetUserPwInfo(join->p, join, &pwp);
202         if (NT_STATUS_IS_OK(status)) {
203                 policy_min_pw_len = pwp.out.info.min_password_length;
204         }
205
206         random_pw = generate_random_str(join, MAX(8, policy_min_pw_len));
207
208         printf("Setting account password '%s'\n", random_pw);
209
210         s.in.user_handle = &join->user_handle;
211         s.in.info = &u;
212         s.in.level = 24;
213
214         encode_pw_buffer(u.info24.password.data, random_pw, STR_UNICODE);
215         u.info24.pw_len = strlen(random_pw);
216
217         status = dcerpc_fetch_session_key(join->p, &session_key);
218         if (!NT_STATUS_IS_OK(status)) {
219                 printf("SetUserInfo level %u - no session key - %s\n",
220                        s.in.level, nt_errstr(status));
221                 torture_leave_domain(join);
222                 goto failed;
223         }
224
225         arcfour_crypt_blob(u.info24.password.data, 516, &session_key);
226
227         status = dcerpc_samr_SetUserInfo(join->p, join, &s);
228         if (!NT_STATUS_IS_OK(status)) {
229                 printf("SetUserInfo failed - %s\n", nt_errstr(status));
230                 goto failed;
231         }
232
233         ZERO_STRUCT(u);
234         s.in.user_handle = &join->user_handle;
235         s.in.info = &u;
236         s.in.level = 21;
237
238         u.info21.acct_flags = acct_type;
239         u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
240         comment.string = talloc_asprintf(join, 
241                                          "Tortured by Samba4: %s", 
242                                          timestring(join, time(NULL)));
243         u.info21.comment = comment;
244         full_name.string = talloc_asprintf(join, 
245                                          "Torture account for Samba4: %s", 
246                                          timestring(join, time(NULL)));
247         u.info21.full_name = full_name;
248
249         u.info21.description.string = talloc_asprintf(join, 
250                                          "Samba4 torture account created by host %s: %s", 
251                                          lp_netbios_name(), timestring(join, time(NULL)));
252
253         printf("Resetting ACB flags, force pw change time\n");
254
255         status = dcerpc_samr_SetUserInfo(join->p, join, &s);
256         if (!NT_STATUS_IS_OK(status)) {
257                 printf("SetUserInfo failed - %s\n", nt_errstr(status));
258                 goto failed;
259         }
260
261         if (random_password) {
262                 *random_password = random_pw;
263         }
264
265         return join;
266
267 failed:
268         torture_leave_domain(join);
269         return NULL;
270 }
271
272
273 struct test_join *torture_join_domain(const char *machine_name, 
274                                       const char *domain,
275                                       uint16_t acct_flags,
276                                       const char **machine_password)
277 {
278         char *username = talloc_asprintf(NULL, "%s$", machine_name);
279         struct test_join *tj = torture_create_testuser(username, domain, acct_flags, machine_password);
280         talloc_free(username);
281         return tj;
282 }
283
284 struct dcerpc_pipe *torture_join_samr_pipe(struct test_join *join) 
285 {
286         return join->p;
287 }
288
289 struct policy_handle *torture_join_samr_user_policy(struct test_join *join) 
290 {
291         return &join->user_handle;
292 }
293
294 /*
295   leave the domain, deleting the machine acct
296 */
297 void torture_leave_domain(struct test_join *join)
298 {
299         struct samr_DeleteUser d;
300         NTSTATUS status;
301
302         if (!GUID_all_zero(&join->user_handle.uuid)) {
303                 d.in.user_handle = &join->user_handle;
304                 d.out.user_handle = &join->user_handle;
305                 
306                 status = dcerpc_samr_DeleteUser(join->p, join, &d);
307                 if (!NT_STATUS_IS_OK(status)) {
308                         printf("Delete of machine account failed\n");
309                 }
310         }
311
312         talloc_free(join);
313 }
314
315 /*
316   return the dom sid for a test join
317 */
318 const char *torture_join_sid(struct test_join *join)
319 {
320         return join->dom_sid;
321 }
322
323
324 struct test_join_ads_dc {
325         struct test_join *join;
326 };
327
328 struct test_join_ads_dc *torture_join_domain_ads_dc(const char *machine_name, 
329                                                     const char *domain,
330                                                     const char **machine_password)
331 {
332         struct test_join_ads_dc *join;
333
334         join = talloc(NULL, struct test_join_ads_dc);
335         if (join == NULL) {
336                 return NULL;
337         }
338
339         join->join = torture_join_domain(machine_name, domain,
340                                         ACB_SVRTRUST,
341                                         machine_password);
342
343         if (!join->join) {
344                 return NULL;
345         }
346
347         /* do netlogon DrsEnumerateDomainTrusts */
348
349         /* modify userAccountControl from 4096 to 532480 */
350         
351         /* modify RDN to OU=Domain Controllers and skip the $ from server name */
352
353         /* ask objectVersion of Schema Partition */
354
355         /* ask rIDManagerReferenz of the Domain Partition */
356
357         /* ask fsMORoleOwner of the RID-Manager$ object
358          * returns CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ...
359          */
360
361         /* ask for dnsHostName of CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
362
363         /* ask for objectGUID of CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
364
365         /* ask for * of CN=Default-First-Site-Name, ... */
366
367         /* search (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<machine_name>$)) in Domain Partition 
368          * attributes : distinguishedName, userAccountControl
369          */
370
371         /* ask * for CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,... 
372          * should fail with noSuchObject
373          */
374
375         /* add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,... 
376          *
377          * objectClass = server
378          * systemFlags = 50000000
379          * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
380          */
381
382         /* ask for * of CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
383          * should fail with noSuchObject
384          */
385
386         /* search for (ncname=<domain_nc>) in CN=Partitions,CN=Configuration,... 
387          * attributes: ncName, dnsRoot
388          */
389
390         /* modify add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
391          * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
392          * should fail with attributeOrValueExists
393          */
394
395         /* modify replace CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
396          * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
397          */
398
399         /* DsReplicaAdd to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
400          * needs to be tested
401          */
402
403         return join;
404 }
405                 
406 void torture_leave_domain_ads_dc(struct test_join_ads_dc *join)
407 {
408
409         if (join->join) {
410                 torture_leave_domain(join->join);
411         }
412
413         talloc_free(join);
414 }