r23271: merge service control pidl change for CloseServiceHandle() from SAMBA_3_0_26
[sfrench/samba-autobuild/.git] / source / 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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
22 */
23
24 #include "includes.h"
25 #include "utils/net.h"
26
27 /* Macro for checking RPC error codes to make things more readable */
28
29 #define CHECK_RPC_ERR(rpc, msg) \
30         if (!NT_STATUS_IS_OK(result = rpc)) { \
31                 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
32                 goto done; \
33         }
34
35 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
36         if (!NT_STATUS_IS_OK(result = rpc)) { \
37                 DEBUG(0, debug_args); \
38                 goto done; \
39         }
40
41 /*******************************************************************
42  Leave an AD domain.  Windows XP disables the machine account.
43  We'll try the same.  The old code would do an LDAP delete.
44  That only worked using the machine creds because added the machine
45  with full control to the computer object's ACL.
46 *******************************************************************/
47
48 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
49                          DOM_SID *dom_sid )
50 {       
51         struct rpc_pipe_client *pipe_hnd = NULL;
52         POLICY_HND sam_pol, domain_pol, user_pol;
53         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
54         char *acct_name;
55         uint32 flags = 0x3e8;
56         const char *const_acct_name;
57         uint32 user_rid;
58         uint32 num_rids, *name_types, *user_rids;
59         SAM_USERINFO_CTR ctr, *qctr = NULL;
60         SAM_USER_INFO_16 p16;
61
62         /* Open the domain */
63         
64         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
65                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
66                         nt_errstr(status) ));
67                 return status;
68         }
69
70         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
71                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
72         if ( !NT_STATUS_IS_OK(status) )
73                 return status;
74
75         
76         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
77                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
78         if ( !NT_STATUS_IS_OK(status) )
79                 return status;
80
81         /* Create domain user */
82         
83         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
84         strlower_m(acct_name);
85         const_acct_name = acct_name;
86
87         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
88                         &domain_pol, flags, 1, &const_acct_name, 
89                         &num_rids, &user_rids, &name_types);
90         if ( !NT_STATUS_IS_OK(status) )
91                 return status;
92
93         if ( name_types[0] != SID_NAME_USER) {
94                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
95                 return NT_STATUS_INVALID_WORKSTATION;
96         }
97
98         user_rid = user_rids[0];
99                 
100         /* Open handle on user */
101
102         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
103                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
104         if ( !NT_STATUS_IS_OK(status) ) {
105                 goto done;
106         }
107         
108         /* Get user info */
109
110         status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
111         if ( !NT_STATUS_IS_OK(status) ) {
112                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
113                 goto done;
114         }
115
116         /* now disable and setuser info */
117         
118         ZERO_STRUCT(ctr);
119         ctr.switch_value = 16;
120         ctr.info.id16 = &p16;
121
122         p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
123
124         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
125                                         &cli->user_session_key, &ctr);
126
127         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
128
129 done:
130         rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
131         rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
132         
133         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
134         
135         return status;
136 }
137
138 /*******************************************************************
139  Store the machine password and domain SID
140  ********************************************************************/
141
142 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
143 {
144         if (!secrets_store_domain_sid(domain, sid)) {
145                 DEBUG(1,("Failed to save domain sid\n"));
146                 return -1;
147         }
148
149         if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
150                 DEBUG(1,("Failed to save machine password\n"));
151                 return -1;
152         }
153
154         return 0;
155 }
156
157 /*******************************************************************
158  ********************************************************************/
159
160 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
161                                 char **domain, DOM_SID **sid )
162 {
163         struct rpc_pipe_client *pipe_hnd = NULL;
164         POLICY_HND lsa_pol;
165         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
166
167         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
168                 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
169                         nt_errstr(status) ));
170                 return status;
171         }
172
173         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
174                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
175         if ( !NT_STATUS_IS_OK(status) )
176                 return status;
177
178         status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, 
179                         &lsa_pol, 5, domain, sid);
180         if ( !NT_STATUS_IS_OK(status) )
181                 return status;
182
183         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
184         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
185
186         /* Bail out if domain didn't get set. */
187         if (!domain) {
188                 DEBUG(0, ("Could not get domain name.\n"));
189                 return NT_STATUS_UNSUCCESSFUL;
190         }
191         
192         return NT_STATUS_OK;
193 }
194
195 /*******************************************************************
196  Do the domain join
197  ********************************************************************/
198  
199 NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
200                            DOM_SID *dom_sid, const char *clear_pw,
201                            enum netdom_domain_t dom_type )
202 {       
203         struct rpc_pipe_client *pipe_hnd = NULL;
204         POLICY_HND sam_pol, domain_pol, user_pol;
205         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206         char *acct_name;
207         const char *const_acct_name;
208         uint32 user_rid;
209         uint32 num_rids, *name_types, *user_rids;
210         uint32 flags = 0x3e8;
211         uint32 acb_info = ACB_WSTRUST;
212         uchar pwbuf[516];
213         SAM_USERINFO_CTR ctr;
214         SAM_USER_INFO_24 p24;
215         SAM_USER_INFO_16 p16;
216         uchar md4_trust_password[16];
217
218         /* Open the domain */
219         
220         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
221                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
222                         nt_errstr(status) ));
223                 return status;
224         }
225
226         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
227                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
228         if ( !NT_STATUS_IS_OK(status) )
229                 return status;
230
231         
232         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
233                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
234         if ( !NT_STATUS_IS_OK(status) )
235                 return status;
236
237         /* Create domain user */
238         
239         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
240         strlower_m(acct_name);
241         const_acct_name = acct_name;
242
243         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
244
245         status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
246                         acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
247
248         if ( !NT_STATUS_IS_OK(status) 
249                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
250         {
251                 d_fprintf(stderr, "Creation of workstation account failed\n");
252
253                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
254                    username/password combo but the user does not have
255                    administrator access. */
256
257                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
258                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
259
260                 return status;
261         }
262
263         /* We *must* do this.... don't ask... */
264
265         if (NT_STATUS_IS_OK(status)) {
266                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
267         }
268
269         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
270                         &domain_pol, flags, 1, &const_acct_name, 
271                         &num_rids, &user_rids, &name_types);
272         if ( !NT_STATUS_IS_OK(status) )
273                 return status;
274
275         if ( name_types[0] != SID_NAME_USER) {
276                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
277                 return NT_STATUS_INVALID_WORKSTATION;
278         }
279
280         user_rid = user_rids[0];
281                 
282         /* Open handle on user */
283
284         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
285                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
286         
287         /* Create a random machine account password */
288
289         E_md4hash( clear_pw, md4_trust_password);
290         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
291
292         /* Set password on machine account */
293
294         ZERO_STRUCT(ctr);
295         ZERO_STRUCT(p24);
296
297         init_sam_user_info24(&p24, (char *)pwbuf,24);
298
299         ctr.switch_value = 24;
300         ctr.info.id24 = &p24;
301
302         status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol, 
303                         24, &cli->user_session_key, &ctr);
304
305         if ( !NT_STATUS_IS_OK(status) ) {
306                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
307                         nt_errstr(status));
308                 return status;
309         }
310
311
312         /* Why do we have to try to (re-)set the ACB to be the same as what
313            we passed in the samr_create_dom_user() call?  When a NT
314            workstation is joined to a domain by an administrator the
315            acb_info is set to 0x80.  For a normal user with "Add
316            workstations to the domain" rights the acb_info is 0x84.  I'm
317            not sure whether it is supposed to make a difference or not.  NT
318            seems to cope with either value so don't bomb out if the set
319            userinfo2 level 0x10 fails.  -tpot */
320
321         ZERO_STRUCT(ctr);
322         ctr.switch_value = 16;
323         ctr.info.id16 = &p16;
324
325         /* Fill in the additional account flags now */
326
327         acb_info |= ACB_PWNOEXP;
328         if ( dom_type == ND_TYPE_AD ) {
329 #if !defined(ENCTYPE_ARCFOUR_HMAC)
330                 acb_info |= ACB_USE_DES_KEY_ONLY;
331 #endif
332                 ;;
333         }
334
335         init_sam_user_info16(&p16, acb_info);
336
337         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
338                                         &cli->user_session_key, &ctr);
339
340         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
341         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
342         
343         return status;
344 }
345