2 Samba Unix/Linux SMB client library
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)
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.
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.
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/>.
25 #include "utils/net.h"
27 /* Macro for checking RPC error codes to make things more readable */
29 #define CHECK_RPC_ERR(rpc, msg) \
30 if (!NT_STATUS_IS_OK(result = rpc)) { \
31 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
35 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
36 if (!NT_STATUS_IS_OK(result = rpc)) { \
37 DEBUG(0, debug_args); \
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 *******************************************************************/
48 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
51 struct rpc_pipe_client *pipe_hnd = NULL;
52 POLICY_HND sam_pol, domain_pol, user_pol;
53 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
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;
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",
69 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
70 pipe_hnd->cli->desthost,
71 SEC_RIGHTS_MAXIMUM_ALLOWED,
73 if ( !NT_STATUS_IS_OK(status) )
77 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
79 SEC_RIGHTS_MAXIMUM_ALLOWED,
82 if ( !NT_STATUS_IS_OK(status) )
85 /* Create domain user */
87 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
88 strlower_m(acct_name);
90 init_lsa_String(&lsa_acct_name, acct_name);
92 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
98 if ( !NT_STATUS_IS_OK(status) )
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;
106 user_rid = user_rids.ids[0];
108 /* Open handle on user */
110 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
112 SEC_RIGHTS_MAXIMUM_ALLOWED,
115 if ( !NT_STATUS_IS_OK(status) ) {
121 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
125 if ( !NT_STATUS_IS_OK(status) ) {
126 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
130 /* now disable and setuser info */
132 info->info16.acct_flags |= ACB_DISABLED;
134 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
139 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
142 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
143 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
145 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
150 /*******************************************************************
151 Store the machine password and domain SID
152 ********************************************************************/
154 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
156 if (!secrets_store_domain_sid(domain, sid)) {
157 DEBUG(1,("Failed to save domain sid\n"));
161 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
162 DEBUG(1,("Failed to save machine password\n"));
169 /*******************************************************************
170 ********************************************************************/
172 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli,
173 const char **domain, DOM_SID **sid )
175 struct rpc_pipe_client *pipe_hnd = NULL;
177 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
178 union lsa_PolicyInformation *info = NULL;
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) ));
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) )
191 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
193 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
195 if ( !NT_STATUS_IS_OK(status) )
198 *domain = info->account_domain.name.string;
199 *sid = info->account_domain.sid;
201 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
202 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
204 /* Bail out if domain didn't get set. */
206 DEBUG(0, ("Could not get domain name.\n"));
207 return NT_STATUS_UNSUCCESSFUL;
213 /*******************************************************************
215 ********************************************************************/
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 )
221 struct rpc_pipe_client *pipe_hnd = NULL;
222 POLICY_HND sam_pol, domain_pol, user_pol;
223 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
225 struct lsa_String lsa_acct_name;
227 uint32 acb_info = ACB_WSTRUST;
230 struct MD5Context md5ctx;
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;
239 /* Open the domain */
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) ));
247 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
248 pipe_hnd->cli->desthost,
249 SEC_RIGHTS_MAXIMUM_ALLOWED,
251 if ( !NT_STATUS_IS_OK(status) )
255 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
257 SEC_RIGHTS_MAXIMUM_ALLOWED,
260 if ( !NT_STATUS_IS_OK(status) )
263 /* Create domain user */
265 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
266 strlower_m(acct_name);
268 init_lsa_String(&lsa_acct_name, acct_name);
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;
277 DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
279 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
288 if ( !NT_STATUS_IS_OK(status)
289 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
291 d_fprintf(stderr, "Creation of workstation account failed\n");
293 /* If NT_STATUS_ACCESS_DENIED then we have a valid
294 username/password combo but the user does not have
295 administrator access. */
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");
303 /* We *must* do this.... don't ask... */
305 if (NT_STATUS_IS_OK(status)) {
306 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
309 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
315 if ( !NT_STATUS_IS_OK(status) )
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;
323 user_rid = user_rids.ids[0];
325 /* Open handle on user */
327 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
329 SEC_RIGHTS_MAXIMUM_ALLOWED,
332 if (!NT_STATUS_IS_OK(status)) {
336 /* Create a random machine account password and generate the hash */
338 E_md4hash(clear_pw, md4_trust_password);
339 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
341 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
342 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
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);
349 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
350 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
352 /* Fill in the additional account flags now */
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;
362 /* Set password and account flags on machine account */
363 ZERO_STRUCT(info.info25);
364 info.info25.info.fields_present = ACCT_NT_PWD_SET |
366 SAMR_FIELD_ACCT_FLAGS;
367 info.info25.info.acct_flags = acb_info;
368 memcpy(&info.info25.password.data, pwbuf, sizeof(pwbuf));
371 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
376 if ( !NT_STATUS_IS_OK(status) ) {
377 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
382 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
383 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */