Add my copyright.
[gd/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    Copyright (C) 2008 Guenther Deschner (gd@samba.org)
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.  
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 user_rid;
56         struct lsa_String lsa_acct_name;
57         struct samr_Ids user_rids;
58         struct samr_Ids name_types;
59         union samr_UserInfo *info = NULL;
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_Connect2(pipe_hnd, mem_ctx,
70                                       pipe_hnd->cli->desthost,
71                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
72                                       &sam_pol);
73         if ( !NT_STATUS_IS_OK(status) )
74                 return status;
75
76
77         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
78                                         &sam_pol,
79                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
80                                         dom_sid,
81                                         &domain_pol);
82         if ( !NT_STATUS_IS_OK(status) )
83                 return status;
84
85         /* Create domain user */
86         
87         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
88         strlower_m(acct_name);
89
90         init_lsa_String(&lsa_acct_name, acct_name);
91
92         status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
93                                          &domain_pol,
94                                          1,
95                                          &lsa_acct_name,
96                                          &user_rids,
97                                          &name_types);
98         if ( !NT_STATUS_IS_OK(status) )
99                 return status;
100
101         if ( name_types.ids[0] != SID_NAME_USER) {
102                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
103                 return NT_STATUS_INVALID_WORKSTATION;
104         }
105
106         user_rid = user_rids.ids[0];
107                 
108         /* Open handle on user */
109
110         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
111                                       &domain_pol,
112                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
113                                       user_rid,
114                                       &user_pol);
115         if ( !NT_STATUS_IS_OK(status) ) {
116                 goto done;
117         }
118         
119         /* Get user info */
120
121         status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
122                                            &user_pol,
123                                            16,
124                                            &info);
125         if ( !NT_STATUS_IS_OK(status) ) {
126                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
127                 goto done;
128         }
129
130         /* now disable and setuser info */
131
132         info->info16.acct_flags |= ACB_DISABLED;
133
134         status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
135                                          &user_pol,
136                                          16,
137                                          info);
138
139         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
140
141 done:
142         rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
143         rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
144         
145         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
146         
147         return status;
148 }
149
150 /*******************************************************************
151  Store the machine password and domain SID
152  ********************************************************************/
153
154 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
155 {
156         if (!secrets_store_domain_sid(domain, sid)) {
157                 DEBUG(1,("Failed to save domain sid\n"));
158                 return -1;
159         }
160
161         if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
162                 DEBUG(1,("Failed to save machine password\n"));
163                 return -1;
164         }
165
166         return 0;
167 }
168
169 /*******************************************************************
170  ********************************************************************/
171
172 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
173                                 const char **domain, DOM_SID **sid )
174 {
175         struct rpc_pipe_client *pipe_hnd = NULL;
176         POLICY_HND lsa_pol;
177         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
178         union lsa_PolicyInformation *info = NULL;
179
180         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
181                 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
182                         nt_errstr(status) ));
183                 return status;
184         }
185
186         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
187                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
188         if ( !NT_STATUS_IS_OK(status) )
189                 return status;
190
191         status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
192                                             &lsa_pol,
193                                             LSA_POLICY_INFO_ACCOUNT_DOMAIN,
194                                             &info);
195         if ( !NT_STATUS_IS_OK(status) )
196                 return status;
197
198         *domain = info->account_domain.name.string;
199         *sid = info->account_domain.sid;
200
201         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
202         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
203
204         /* Bail out if domain didn't get set. */
205         if (!domain) {
206                 DEBUG(0, ("Could not get domain name.\n"));
207                 return NT_STATUS_UNSUCCESSFUL;
208         }
209         
210         return NT_STATUS_OK;
211 }
212
213 /*******************************************************************
214  Do the domain join
215  ********************************************************************/
216  
217 NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
218                            DOM_SID *dom_sid, const char *clear_pw,
219                            enum netdom_domain_t dom_type )
220 {       
221         struct rpc_pipe_client *pipe_hnd = NULL;
222         POLICY_HND sam_pol, domain_pol, user_pol;
223         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
224         char *acct_name;
225         struct lsa_String lsa_acct_name;
226         uint32 user_rid;
227         uint32 acb_info = ACB_WSTRUST;
228         uint32 acct_flags;
229         uchar pwbuf[532];
230         struct MD5Context md5ctx;
231         uchar md5buffer[16];
232         DATA_BLOB digested_session_key;
233         uchar md4_trust_password[16];
234         uint32_t access_granted = 0;
235         struct samr_Ids user_rids;
236         struct samr_Ids name_types;
237         union samr_UserInfo info;
238
239         /* Open the domain */
240         
241         if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
242                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
243                         nt_errstr(status) ));
244                 return status;
245         }
246
247         status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
248                                       pipe_hnd->cli->desthost,
249                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
250                                       &sam_pol);
251         if ( !NT_STATUS_IS_OK(status) )
252                 return status;
253
254
255         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
256                                         &sam_pol,
257                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
258                                         dom_sid,
259                                         &domain_pol);
260         if ( !NT_STATUS_IS_OK(status) )
261                 return status;
262
263         /* Create domain user */
264         
265         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
266         strlower_m(acct_name);
267
268         init_lsa_String(&lsa_acct_name, acct_name);
269
270         /* Don't try to set any acb_info flags other than ACB_WSTRUST */
271         acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
272                      SEC_STD_WRITE_DAC | SEC_STD_DELETE |
273                      SAMR_USER_ACCESS_SET_PASSWORD |
274                      SAMR_USER_ACCESS_GET_ATTRIBUTES |
275                      SAMR_USER_ACCESS_SET_ATTRIBUTES;
276
277         DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
278
279         status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
280                                          &domain_pol,
281                                          &lsa_acct_name,
282                                          acb_info,
283                                          acct_flags,
284                                          &user_pol,
285                                          &access_granted,
286                                          &user_rid);
287
288         if ( !NT_STATUS_IS_OK(status) 
289                 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
290         {
291                 d_fprintf(stderr, "Creation of workstation account failed\n");
292
293                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
294                    username/password combo but the user does not have
295                    administrator access. */
296
297                 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
298                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
299
300                 return status;
301         }
302
303         /* We *must* do this.... don't ask... */
304
305         if (NT_STATUS_IS_OK(status)) {
306                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
307         }
308
309         status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
310                                          &domain_pol,
311                                          1,
312                                          &lsa_acct_name,
313                                          &user_rids,
314                                          &name_types);
315         if ( !NT_STATUS_IS_OK(status) )
316                 return status;
317
318         if ( name_types.ids[0] != SID_NAME_USER) {
319                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
320                 return NT_STATUS_INVALID_WORKSTATION;
321         }
322
323         user_rid = user_rids.ids[0];
324                 
325         /* Open handle on user */
326
327         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
328                                       &domain_pol,
329                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
330                                       user_rid,
331                                       &user_pol);
332         if (!NT_STATUS_IS_OK(status)) {
333                 return status;
334         }
335         
336         /* Create a random machine account password and generate the hash */
337
338         E_md4hash(clear_pw, md4_trust_password);
339         encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
340         
341         generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
342         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
343         
344         MD5Init(&md5ctx);
345         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
346         MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
347         MD5Final(digested_session_key.data, &md5ctx);
348         
349         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
350         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
351
352         /* Fill in the additional account flags now */
353
354         acb_info |= ACB_PWNOEXP;
355         if ( dom_type == ND_TYPE_AD ) {
356 #if !defined(ENCTYPE_ARCFOUR_HMAC)
357                 acb_info |= ACB_USE_DES_KEY_ONLY;
358 #endif
359                 ;;
360         }
361
362         /* Set password and account flags on machine account */
363         ZERO_STRUCT(info.info25);
364         info.info25.info.fields_present = ACCT_NT_PWD_SET |
365                                           ACCT_LM_PWD_SET |
366                                           SAMR_FIELD_ACCT_FLAGS;
367         info.info25.info.acct_flags = acb_info;
368         memcpy(&info.info25.password.data, pwbuf, sizeof(pwbuf));
369
370
371         status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
372                                          &user_pol,
373                                          25,
374                                          &info);
375
376         if ( !NT_STATUS_IS_OK(status) ) {
377                 d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
378                         nt_errstr(status));
379                 return status;
380         }
381
382         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
383         cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
384         
385         return status;
386 }
387