Merge branch 'v3-2-test-merge' into v3-2-stable
[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 /*******************************************************************
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 fields_present;
212         uchar pwbuf[532];
213         SAM_USERINFO_CTR ctr;
214         SAM_USER_INFO_25 p25;
215         const int infolevel = 25;
216         struct MD5Context md5ctx;
217         uchar md5buffer[16];
218         DATA_BLOB digested_session_key;
219         uchar md4_trust_password[16];
220
221         /* Open the domain */
222         
223         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
224                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
225                         nt_errstr(status) ));
226                 return status;
227         }
228
229         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
230                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
231         if ( !NT_STATUS_IS_OK(status) )
232                 return status;
233
234         
235         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
236                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
237         if ( !NT_STATUS_IS_OK(status) )
238                 return status;
239
240         /* Create domain user */
241         
242         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
243         strlower_m(acct_name);
244         const_acct_name = acct_name;
245
246         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
247
248         status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
249                         acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
250
251         if ( !NT_STATUS_IS_OK(status) 
252                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
253         {
254                 d_fprintf(stderr, "Creation of workstation account failed\n");
255
256                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
257                    username/password combo but the user does not have
258                    administrator access. */
259
260                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
261                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
262
263                 return status;
264         }
265
266         /* We *must* do this.... don't ask... */
267
268         if (NT_STATUS_IS_OK(status)) {
269                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
270         }
271
272         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
273                         &domain_pol, flags, 1, &const_acct_name, 
274                         &num_rids, &user_rids, &name_types);
275         if ( !NT_STATUS_IS_OK(status) )
276                 return status;
277
278         if ( name_types[0] != SID_NAME_USER) {
279                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
280                 return NT_STATUS_INVALID_WORKSTATION;
281         }
282
283         user_rid = user_rids[0];
284                 
285         /* Open handle on user */
286
287         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
288                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
289         if (!NT_STATUS_IS_OK(status)) {
290                 return status;
291         }
292         
293         /* Create a random machine account password and generate the hash */
294
295         E_md4hash(clear_pw, md4_trust_password);
296         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
297         
298         generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
299         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
300         
301         MD5Init(&md5ctx);
302         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
303         MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
304         MD5Final(digested_session_key.data, &md5ctx);
305         
306         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
307         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
308
309         /* Fill in the additional account flags now */
310
311         acb_info |= ACB_PWNOEXP;
312         if ( dom_type == ND_TYPE_AD ) {
313 #if !defined(ENCTYPE_ARCFOUR_HMAC)
314                 acb_info |= ACB_USE_DES_KEY_ONLY;
315 #endif
316                 ;;
317         }
318
319         /* Set password and account flags on machine account */
320
321         ZERO_STRUCT(ctr);
322         ZERO_STRUCT(p25);
323
324         fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
325         init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
326
327         ctr.switch_value = infolevel;
328         ctr.info.id25    = &p25;
329
330         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
331                                            infolevel, &cli->user_session_key, &ctr);
332
333         if ( !NT_STATUS_IS_OK(status) ) {
334                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
335                         nt_errstr(status));
336                 return status;
337         }
338
339         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
340         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
341         
342         return status;
343 }
344