source: branches/samba-3.0/source/utils/net_domain.c

Last change on this file was 140, checked in by Paul Smedley, 17 years ago

Update branch to 3.0.31 release

File size: 11.2 KB
Line 
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
48NTSTATUS 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
129done:
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
142int 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
160NTSTATUS 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
199NTSTATUS 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 uint32 acct_flags=0;
213 uint32 fields_present;
214 uchar pwbuf[532];
215 SAM_USERINFO_CTR ctr;
216 SAM_USER_INFO_24 p24;
217 SAM_USER_INFO_25 p25;
218 const int infolevel = 25;
219 struct MD5Context md5ctx;
220 uchar md5buffer[16];
221 DATA_BLOB digested_session_key;
222 uchar md4_trust_password[16];
223
224 /* Open the domain */
225
226 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
227 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
228 nt_errstr(status) ));
229 return status;
230 }
231
232 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
233 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
234 if ( !NT_STATUS_IS_OK(status) )
235 return status;
236
237
238 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
239 SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
240 if ( !NT_STATUS_IS_OK(status) )
241 return status;
242
243 /* Create domain user */
244
245 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
246 strlower_m(acct_name);
247 const_acct_name = acct_name;
248
249 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
250
251 acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE |
252 SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC |
253 SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR |
254 SAMR_USER_SETATTR;
255 DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
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_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
342
343 uchar pwbuf2[516];
344
345 ZERO_STRUCT(p24);
346
347 encode_pw_buffer(pwbuf2, clear_pw, STR_UNICODE);
348
349 /* retry with level 24 */
350 init_sam_user_info24(&p24, (char *)pwbuf2, 24);
351
352 ctr.switch_value = 24;
353 ctr.info.id24 = &p24;
354
355 status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx,
356 &user_pol,
357 24,
358 &cli->user_session_key,
359 &ctr);
360 }
361
362 if ( !NT_STATUS_IS_OK(status) ) {
363 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
364 nt_errstr(status));
365 return status;
366 }
367
368 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
369 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
370
371 return status;
372}
373
Note: See TracBrowser for help on using the repository browser.