Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[ira/wip.git] / source3 / utils / net_domain.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  
21 */
22
23 #include "includes.h"
24 #include "utils/net.h"
25
26 /* Macro for checking RPC error codes to make things more readable */
27
28 #define CHECK_RPC_ERR(rpc, msg) \
29         if (!NT_STATUS_IS_OK(result = rpc)) { \
30                 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
31                 goto done; \
32         }
33
34 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
35         if (!NT_STATUS_IS_OK(result = rpc)) { \
36                 DEBUG(0, debug_args); \
37                 goto done; \
38         }
39
40 static void init_lsa_String(struct lsa_String *name, const char *s)
41 {
42         name->string = s;
43 }
44
45 /*******************************************************************
46  Leave an AD domain.  Windows XP disables the machine account.
47  We'll try the same.  The old code would do an LDAP delete.
48  That only worked using the machine creds because added the machine
49  with full control to the computer object's ACL.
50 *******************************************************************/
51
52 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
53                          DOM_SID *dom_sid )
54 {       
55         struct rpc_pipe_client *pipe_hnd = NULL;
56         POLICY_HND sam_pol, domain_pol, user_pol;
57         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
58         char *acct_name;
59         uint32 flags = 0x3e8;
60         const char *const_acct_name;
61         uint32 user_rid;
62         uint32 num_rids, *name_types, *user_rids;
63         SAM_USERINFO_CTR ctr, *qctr = NULL;
64         SAM_USER_INFO_16 p16;
65
66         /* Open the domain */
67         
68         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
69                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
70                         nt_errstr(status) ));
71                 return status;
72         }
73
74         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
75                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
76         if ( !NT_STATUS_IS_OK(status) )
77                 return status;
78
79
80         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
81                                         &sam_pol,
82                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
83                                         dom_sid,
84                                         &domain_pol);
85         if ( !NT_STATUS_IS_OK(status) )
86                 return status;
87
88         /* Create domain user */
89         
90         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
91         strlower_m(acct_name);
92         const_acct_name = acct_name;
93
94         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
95                         &domain_pol, flags, 1, &const_acct_name, 
96                         &num_rids, &user_rids, &name_types);
97         if ( !NT_STATUS_IS_OK(status) )
98                 return status;
99
100         if ( name_types[0] != SID_NAME_USER) {
101                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
102                 return NT_STATUS_INVALID_WORKSTATION;
103         }
104
105         user_rid = user_rids[0];
106                 
107         /* Open handle on user */
108
109         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
110                                       &domain_pol,
111                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
112                                       user_rid,
113                                       &user_pol);
114         if ( !NT_STATUS_IS_OK(status) ) {
115                 goto done;
116         }
117         
118         /* Get user info */
119
120         status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
121         if ( !NT_STATUS_IS_OK(status) ) {
122                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
123                 goto done;
124         }
125
126         /* now disable and setuser info */
127         
128         ZERO_STRUCT(ctr);
129         ctr.switch_value = 16;
130         ctr.info.id16 = &p16;
131
132         p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
133
134         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
135                                         &cli->user_session_key, &ctr);
136
137         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
138
139 done:
140         rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
141         rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
142         
143         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
144         
145         return status;
146 }
147
148 /*******************************************************************
149  Store the machine password and domain SID
150  ********************************************************************/
151
152 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
153 {
154         if (!secrets_store_domain_sid(domain, sid)) {
155                 DEBUG(1,("Failed to save domain sid\n"));
156                 return -1;
157         }
158
159         if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
160                 DEBUG(1,("Failed to save machine password\n"));
161                 return -1;
162         }
163
164         return 0;
165 }
166
167 /*******************************************************************
168  ********************************************************************/
169
170 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
171                                 const char **domain, DOM_SID **sid )
172 {
173         struct rpc_pipe_client *pipe_hnd = NULL;
174         POLICY_HND lsa_pol;
175         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
176
177         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
178                 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
179                         nt_errstr(status) ));
180                 return status;
181         }
182
183         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
184                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
185         if ( !NT_STATUS_IS_OK(status) )
186                 return status;
187
188         status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, 
189                         &lsa_pol, 5, domain, sid);
190         if ( !NT_STATUS_IS_OK(status) )
191                 return status;
192
193         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
194         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
195
196         /* Bail out if domain didn't get set. */
197         if (!domain) {
198                 DEBUG(0, ("Could not get domain name.\n"));
199                 return NT_STATUS_UNSUCCESSFUL;
200         }
201         
202         return NT_STATUS_OK;
203 }
204
205 /*******************************************************************
206  Do the domain join
207  ********************************************************************/
208  
209 NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
210                            DOM_SID *dom_sid, const char *clear_pw,
211                            enum netdom_domain_t dom_type )
212 {       
213         struct rpc_pipe_client *pipe_hnd = NULL;
214         POLICY_HND sam_pol, domain_pol, user_pol;
215         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
216         char *acct_name;
217         const char *const_acct_name;
218         struct lsa_String lsa_acct_name;
219         uint32 user_rid;
220         uint32 num_rids, *name_types, *user_rids;
221         uint32 flags = 0x3e8;
222         uint32 acb_info = ACB_WSTRUST;
223         uint32 acct_flags;
224         uint32 fields_present;
225         uchar pwbuf[532];
226         SAM_USERINFO_CTR ctr;
227         SAM_USER_INFO_25 p25;
228         const int infolevel = 25;
229         struct MD5Context md5ctx;
230         uchar md5buffer[16];
231         DATA_BLOB digested_session_key;
232         uchar md4_trust_password[16];
233         uint32_t access_granted = 0;
234
235         /* Open the domain */
236         
237         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
238                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
239                         nt_errstr(status) ));
240                 return status;
241         }
242
243         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
244                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
245         if ( !NT_STATUS_IS_OK(status) )
246                 return status;
247
248
249         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
250                                         &sam_pol,
251                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
252                                         dom_sid,
253                                         &domain_pol);
254         if ( !NT_STATUS_IS_OK(status) )
255                 return status;
256
257         /* Create domain user */
258         
259         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
260         strlower_m(acct_name);
261         const_acct_name = acct_name;
262
263         init_lsa_String(&lsa_acct_name, acct_name);
264
265         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
266         acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
267                      SEC_STD_WRITE_DAC | SEC_STD_DELETE |
268                      SAMR_USER_ACCESS_SET_PASSWORD |
269                      SAMR_USER_ACCESS_GET_ATTRIBUTES |
270                      SAMR_USER_ACCESS_SET_ATTRIBUTES;
271
272         DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
273
274         status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
275                                          &domain_pol,
276                                          &lsa_acct_name,
277                                          acb_info,
278                                          acct_flags,
279                                          &user_pol,
280                                          &access_granted,
281                                          &user_rid);
282
283         if ( !NT_STATUS_IS_OK(status) 
284                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
285         {
286                 d_fprintf(stderr, "Creation of workstation account failed\n");
287
288                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
289                    username/password combo but the user does not have
290                    administrator access. */
291
292                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
293                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
294
295                 return status;
296         }
297
298         /* We *must* do this.... don't ask... */
299
300         if (NT_STATUS_IS_OK(status)) {
301                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
302         }
303
304         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
305                         &domain_pol, flags, 1, &const_acct_name, 
306                         &num_rids, &user_rids, &name_types);
307         if ( !NT_STATUS_IS_OK(status) )
308                 return status;
309
310         if ( name_types[0] != SID_NAME_USER) {
311                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
312                 return NT_STATUS_INVALID_WORKSTATION;
313         }
314
315         user_rid = user_rids[0];
316                 
317         /* Open handle on user */
318
319         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
320                                       &domain_pol,
321                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
322                                       user_rid,
323                                       &user_pol);
324         if (!NT_STATUS_IS_OK(status)) {
325                 return status;
326         }
327         
328         /* Create a random machine account password and generate the hash */
329
330         E_md4hash(clear_pw, md4_trust_password);
331         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
332         
333         generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
334         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
335         
336         MD5Init(&md5ctx);
337         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
338         MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
339         MD5Final(digested_session_key.data, &md5ctx);
340         
341         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
342         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
343
344         /* Fill in the additional account flags now */
345
346         acb_info |= ACB_PWNOEXP;
347         if ( dom_type == ND_TYPE_AD ) {
348 #if !defined(ENCTYPE_ARCFOUR_HMAC)
349                 acb_info |= ACB_USE_DES_KEY_ONLY;
350 #endif
351                 ;;
352         }
353
354         /* Set password and account flags on machine account */
355
356         ZERO_STRUCT(ctr);
357         ZERO_STRUCT(p25);
358
359         fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
360         init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
361
362         ctr.switch_value = infolevel;
363         ctr.info.id25    = &p25;
364
365         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
366                                            infolevel, &cli->user_session_key, &ctr);
367
368         if ( !NT_STATUS_IS_OK(status) ) {
369                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
370                         nt_errstr(status));
371                 return status;
372         }
373
374         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
375         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
376         
377         return status;
378 }
379