Merge branch 'ctdb-merge' into dmapi-integration
[samba.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 /*******************************************************************
41  Leave an AD domain.  Windows XP disables the machine account.
42  We'll try the same.  The old code would do an LDAP delete.
43  That only worked using the machine creds because added the machine
44  with full control to the computer object's ACL.
45 *******************************************************************/
46
47 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
48                          DOM_SID *dom_sid )
49 {       
50         struct rpc_pipe_client *pipe_hnd = NULL;
51         POLICY_HND sam_pol, domain_pol, user_pol;
52         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
53         char *acct_name;
54         uint32 flags = 0x3e8;
55         const char *const_acct_name;
56         uint32 user_rid;
57         uint32 num_rids, *name_types, *user_rids;
58         SAM_USERINFO_CTR ctr, *qctr = NULL;
59         SAM_USER_INFO_16 p16;
60
61         /* Open the domain */
62         
63         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
64                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
65                         nt_errstr(status) ));
66                 return status;
67         }
68
69         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
70                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
71         if ( !NT_STATUS_IS_OK(status) )
72                 return status;
73
74         
75         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
76                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
77         if ( !NT_STATUS_IS_OK(status) )
78                 return status;
79
80         /* Create domain user */
81         
82         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
83         strlower_m(acct_name);
84         const_acct_name = acct_name;
85
86         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
87                         &domain_pol, flags, 1, &const_acct_name, 
88                         &num_rids, &user_rids, &name_types);
89         if ( !NT_STATUS_IS_OK(status) )
90                 return status;
91
92         if ( name_types[0] != SID_NAME_USER) {
93                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
94                 return NT_STATUS_INVALID_WORKSTATION;
95         }
96
97         user_rid = user_rids[0];
98                 
99         /* Open handle on user */
100
101         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
102                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
103         if ( !NT_STATUS_IS_OK(status) ) {
104                 goto done;
105         }
106         
107         /* Get user info */
108
109         status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
110         if ( !NT_STATUS_IS_OK(status) ) {
111                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
112                 goto done;
113         }
114
115         /* now disable and setuser info */
116         
117         ZERO_STRUCT(ctr);
118         ctr.switch_value = 16;
119         ctr.info.id16 = &p16;
120
121         p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
122
123         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
124                                         &cli->user_session_key, &ctr);
125
126         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
127
128 done:
129         rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
130         rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
131         
132         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
133         
134         return status;
135 }
136
137 /*******************************************************************
138  Store the machine password and domain SID
139  ********************************************************************/
140
141 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
142 {
143         if (!secrets_store_domain_sid(domain, sid)) {
144                 DEBUG(1,("Failed to save domain sid\n"));
145                 return -1;
146         }
147
148         if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
149                 DEBUG(1,("Failed to save machine password\n"));
150                 return -1;
151         }
152
153         return 0;
154 }
155
156 /*******************************************************************
157  ********************************************************************/
158
159 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
160                                 const char **domain, DOM_SID **sid )
161 {
162         struct rpc_pipe_client *pipe_hnd = NULL;
163         POLICY_HND lsa_pol;
164         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
165
166         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
167                 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
168                         nt_errstr(status) ));
169                 return status;
170         }
171
172         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
173                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
174         if ( !NT_STATUS_IS_OK(status) )
175                 return status;
176
177         status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, 
178                         &lsa_pol, 5, domain, sid);
179         if ( !NT_STATUS_IS_OK(status) )
180                 return status;
181
182         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
183         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
184
185         /* Bail out if domain didn't get set. */
186         if (!domain) {
187                 DEBUG(0, ("Could not get domain name.\n"));
188                 return NT_STATUS_UNSUCCESSFUL;
189         }
190         
191         return NT_STATUS_OK;
192 }
193
194 /*******************************************************************
195  Do the domain join
196  ********************************************************************/
197  
198 NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
199                            DOM_SID *dom_sid, const char *clear_pw,
200                            enum netdom_domain_t dom_type )
201 {       
202         struct rpc_pipe_client *pipe_hnd = NULL;
203         POLICY_HND sam_pol, domain_pol, user_pol;
204         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
205         char *acct_name;
206         const char *const_acct_name;
207         uint32 user_rid;
208         uint32 num_rids, *name_types, *user_rids;
209         uint32 flags = 0x3e8;
210         uint32 acb_info = ACB_WSTRUST;
211         uint32 acct_flags;
212         uint32 fields_present;
213         uchar pwbuf[532];
214         SAM_USERINFO_CTR ctr;
215         SAM_USER_INFO_25 p25;
216         const int infolevel = 25;
217         struct MD5Context md5ctx;
218         uchar md5buffer[16];
219         DATA_BLOB digested_session_key;
220         uchar md4_trust_password[16];
221
222         /* Open the domain */
223         
224         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
225                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
226                         nt_errstr(status) ));
227                 return status;
228         }
229
230         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
231                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
232         if ( !NT_STATUS_IS_OK(status) )
233                 return status;
234
235         
236         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
237                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
238         if ( !NT_STATUS_IS_OK(status) )
239                 return status;
240
241         /* Create domain user */
242         
243         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
244         strlower_m(acct_name);
245         const_acct_name = acct_name;
246
247         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
248         acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
249                      SEC_STD_WRITE_DAC | SEC_STD_DELETE |
250                      SAMR_USER_ACCESS_SET_PASSWORD |
251                      SAMR_USER_ACCESS_GET_ATTRIBUTES |
252                      SAMR_USER_ACCESS_SET_ATTRIBUTES;
253
254         DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
255
256         status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
257                         acct_name, acb_info, acct_flags, &user_pol, &user_rid);
258
259         if ( !NT_STATUS_IS_OK(status) 
260                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
261         {
262                 d_fprintf(stderr, "Creation of workstation account failed\n");
263
264                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
265                    username/password combo but the user does not have
266                    administrator access. */
267
268                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
269                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
270
271                 return status;
272         }
273
274         /* We *must* do this.... don't ask... */
275
276         if (NT_STATUS_IS_OK(status)) {
277                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
278         }
279
280         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
281                         &domain_pol, flags, 1, &const_acct_name, 
282                         &num_rids, &user_rids, &name_types);
283         if ( !NT_STATUS_IS_OK(status) )
284                 return status;
285
286         if ( name_types[0] != SID_NAME_USER) {
287                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
288                 return NT_STATUS_INVALID_WORKSTATION;
289         }
290
291         user_rid = user_rids[0];
292                 
293         /* Open handle on user */
294
295         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
296                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
297         if (!NT_STATUS_IS_OK(status)) {
298                 return status;
299         }
300         
301         /* Create a random machine account password and generate the hash */
302
303         E_md4hash(clear_pw, md4_trust_password);
304         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
305         
306         generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
307         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
308         
309         MD5Init(&md5ctx);
310         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
311         MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
312         MD5Final(digested_session_key.data, &md5ctx);
313         
314         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
315         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
316
317         /* Fill in the additional account flags now */
318
319         acb_info |= ACB_PWNOEXP;
320         if ( dom_type == ND_TYPE_AD ) {
321 #if !defined(ENCTYPE_ARCFOUR_HMAC)
322                 acb_info |= ACB_USE_DES_KEY_ONLY;
323 #endif
324                 ;;
325         }
326
327         /* Set password and account flags on machine account */
328
329         ZERO_STRUCT(ctr);
330         ZERO_STRUCT(p25);
331
332         fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
333         init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
334
335         ctr.switch_value = infolevel;
336         ctr.info.id25    = &p25;
337
338         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
339                                            infolevel, &cli->user_session_key, &ctr);
340
341         if ( !NT_STATUS_IS_OK(status) ) {
342                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
343                         nt_errstr(status));
344                 return status;
345         }
346
347         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
348         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
349         
350         return status;
351 }
352