r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.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 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                                 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         uchar pwbuf[516];
212         SAM_USERINFO_CTR ctr;
213         SAM_USER_INFO_24 p24;
214         SAM_USER_INFO_16 p16;
215         uchar md4_trust_password[16];
216
217         /* Open the domain */
218         
219         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
220                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
221                         nt_errstr(status) ));
222                 return status;
223         }
224
225         status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
226                         SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
227         if ( !NT_STATUS_IS_OK(status) )
228                 return status;
229
230         
231         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
232                         SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
233         if ( !NT_STATUS_IS_OK(status) )
234                 return status;
235
236         /* Create domain user */
237         
238         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
239         strlower_m(acct_name);
240         const_acct_name = acct_name;
241
242         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
243
244         status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
245                         acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
246
247         if ( !NT_STATUS_IS_OK(status) 
248                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
249         {
250                 d_fprintf(stderr, "Creation of workstation account failed\n");
251
252                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
253                    username/password combo but the user does not have
254                    administrator access. */
255
256                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
257                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
258
259                 return status;
260         }
261
262         /* We *must* do this.... don't ask... */
263
264         if (NT_STATUS_IS_OK(status)) {
265                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
266         }
267
268         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
269                         &domain_pol, flags, 1, &const_acct_name, 
270                         &num_rids, &user_rids, &name_types);
271         if ( !NT_STATUS_IS_OK(status) )
272                 return status;
273
274         if ( name_types[0] != SID_NAME_USER) {
275                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
276                 return NT_STATUS_INVALID_WORKSTATION;
277         }
278
279         user_rid = user_rids[0];
280                 
281         /* Open handle on user */
282
283         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
284                         SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
285         
286         /* Create a random machine account password */
287
288         E_md4hash( clear_pw, md4_trust_password);
289         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
290
291         /* Set password on machine account */
292
293         ZERO_STRUCT(ctr);
294         ZERO_STRUCT(p24);
295
296         init_sam_user_info24(&p24, (char *)pwbuf,24);
297
298         ctr.switch_value = 24;
299         ctr.info.id24 = &p24;
300
301         status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol, 
302                         24, &cli->user_session_key, &ctr);
303
304         if ( !NT_STATUS_IS_OK(status) ) {
305                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
306                         nt_errstr(status));
307                 return status;
308         }
309
310
311         /* Why do we have to try to (re-)set the ACB to be the same as what
312            we passed in the samr_create_dom_user() call?  When a NT
313            workstation is joined to a domain by an administrator the
314            acb_info is set to 0x80.  For a normal user with "Add
315            workstations to the domain" rights the acb_info is 0x84.  I'm
316            not sure whether it is supposed to make a difference or not.  NT
317            seems to cope with either value so don't bomb out if the set
318            userinfo2 level 0x10 fails.  -tpot */
319
320         ZERO_STRUCT(ctr);
321         ctr.switch_value = 16;
322         ctr.info.id16 = &p16;
323
324         /* Fill in the additional account flags now */
325
326         acb_info |= ACB_PWNOEXP;
327         if ( dom_type == ND_TYPE_AD ) {
328 #if !defined(ENCTYPE_ARCFOUR_HMAC)
329                 acb_info |= ACB_USE_DES_KEY_ONLY;
330 #endif
331                 ;;
332         }
333
334         init_sam_user_info16(&p16, acb_info);
335
336         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
337                                         &cli->user_session_key, &ctr);
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