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)
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.
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.
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/>.
24 #include "utils/net.h"
26 /* Macro for checking RPC error codes to make things more readable */
28 #define CHECK_RPC_ERR(rpc, msg) \
29 if (!NT_STATUS_IS_OK(result = rpc)) { \
30 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
34 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
35 if (!NT_STATUS_IS_OK(result = rpc)) { \
36 DEBUG(0, debug_args); \
40 static void init_lsa_String(struct lsa_String *name, const char *s)
45 /*******************************************************************
46 Leave an AD domain. Windows XP disables the machine account.
47 We'll try the same. The old code would do an LDAP delete.
48 That only worked using the machine creds because added the machine
49 with full control to the computer object's ACL.
50 *******************************************************************/
52 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
55 struct rpc_pipe_client *pipe_hnd = NULL;
56 POLICY_HND sam_pol, domain_pol, user_pol;
57 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
60 const char *const_acct_name;
62 uint32 num_rids, *name_types, *user_rids;
63 SAM_USERINFO_CTR ctr, *qctr = NULL;
68 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
69 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
74 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
75 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
76 if ( !NT_STATUS_IS_OK(status) )
80 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
82 SEC_RIGHTS_MAXIMUM_ALLOWED,
85 if ( !NT_STATUS_IS_OK(status) )
88 /* Create domain user */
90 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
91 strlower_m(acct_name);
92 const_acct_name = acct_name;
94 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
95 &domain_pol, flags, 1, &const_acct_name,
96 &num_rids, &user_rids, &name_types);
97 if ( !NT_STATUS_IS_OK(status) )
100 if ( name_types[0] != SID_NAME_USER) {
101 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
102 return NT_STATUS_INVALID_WORKSTATION;
105 user_rid = user_rids[0];
107 /* Open handle on user */
109 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
111 SEC_RIGHTS_MAXIMUM_ALLOWED,
114 if ( !NT_STATUS_IS_OK(status) ) {
120 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
121 if ( !NT_STATUS_IS_OK(status) ) {
122 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
126 /* now disable and setuser info */
129 ctr.switch_value = 16;
130 ctr.info.id16 = &p16;
132 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
134 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
135 &cli->user_session_key, &ctr);
137 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
140 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
141 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
143 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
148 /*******************************************************************
149 Store the machine password and domain SID
150 ********************************************************************/
152 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
154 if (!secrets_store_domain_sid(domain, sid)) {
155 DEBUG(1,("Failed to save domain sid\n"));
159 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
160 DEBUG(1,("Failed to save machine password\n"));
167 /*******************************************************************
168 ********************************************************************/
170 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli,
171 const char **domain, DOM_SID **sid )
173 struct rpc_pipe_client *pipe_hnd = NULL;
175 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
177 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
178 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
179 nt_errstr(status) ));
183 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
184 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
185 if ( !NT_STATUS_IS_OK(status) )
188 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
189 &lsa_pol, 5, domain, sid);
190 if ( !NT_STATUS_IS_OK(status) )
193 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
194 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
196 /* Bail out if domain didn't get set. */
198 DEBUG(0, ("Could not get domain name.\n"));
199 return NT_STATUS_UNSUCCESSFUL;
205 /*******************************************************************
207 ********************************************************************/
209 NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
210 DOM_SID *dom_sid, const char *clear_pw,
211 enum netdom_domain_t dom_type )
213 struct rpc_pipe_client *pipe_hnd = NULL;
214 POLICY_HND sam_pol, domain_pol, user_pol;
215 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
217 const char *const_acct_name;
218 struct lsa_String lsa_acct_name;
220 uint32 num_rids, *name_types, *user_rids;
221 uint32 flags = 0x3e8;
222 uint32 acb_info = ACB_WSTRUST;
224 uint32 fields_present;
226 SAM_USERINFO_CTR ctr;
227 SAM_USER_INFO_25 p25;
228 const int infolevel = 25;
229 struct MD5Context md5ctx;
231 DATA_BLOB digested_session_key;
232 uchar md4_trust_password[16];
233 uint32_t access_granted = 0;
235 /* Open the domain */
237 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
238 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
239 nt_errstr(status) ));
243 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
244 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
245 if ( !NT_STATUS_IS_OK(status) )
249 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
251 SEC_RIGHTS_MAXIMUM_ALLOWED,
254 if ( !NT_STATUS_IS_OK(status) )
257 /* Create domain user */
259 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
260 strlower_m(acct_name);
261 const_acct_name = acct_name;
263 init_lsa_String(&lsa_acct_name, acct_name);
265 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
266 acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
267 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
268 SAMR_USER_ACCESS_SET_PASSWORD |
269 SAMR_USER_ACCESS_GET_ATTRIBUTES |
270 SAMR_USER_ACCESS_SET_ATTRIBUTES;
272 DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
274 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
283 if ( !NT_STATUS_IS_OK(status)
284 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
286 d_fprintf(stderr, "Creation of workstation account failed\n");
288 /* If NT_STATUS_ACCESS_DENIED then we have a valid
289 username/password combo but the user does not have
290 administrator access. */
292 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
293 d_fprintf(stderr, "User specified does not have administrator privileges\n");
298 /* We *must* do this.... don't ask... */
300 if (NT_STATUS_IS_OK(status)) {
301 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
304 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
305 &domain_pol, flags, 1, &const_acct_name,
306 &num_rids, &user_rids, &name_types);
307 if ( !NT_STATUS_IS_OK(status) )
310 if ( name_types[0] != SID_NAME_USER) {
311 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
312 return NT_STATUS_INVALID_WORKSTATION;
315 user_rid = user_rids[0];
317 /* Open handle on user */
319 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
321 SEC_RIGHTS_MAXIMUM_ALLOWED,
324 if (!NT_STATUS_IS_OK(status)) {
328 /* Create a random machine account password and generate the hash */
330 E_md4hash(clear_pw, md4_trust_password);
331 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
333 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
334 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
337 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
338 MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
339 MD5Final(digested_session_key.data, &md5ctx);
341 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
342 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
344 /* Fill in the additional account flags now */
346 acb_info |= ACB_PWNOEXP;
347 if ( dom_type == ND_TYPE_AD ) {
348 #if !defined(ENCTYPE_ARCFOUR_HMAC)
349 acb_info |= ACB_USE_DES_KEY_ONLY;
354 /* Set password and account flags on machine account */
359 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
360 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
362 ctr.switch_value = infolevel;
363 ctr.info.id25 = &p25;
365 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
366 infolevel, &cli->user_session_key, &ctr);
368 if ( !NT_STATUS_IS_OK(status) ) {
369 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
374 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
375 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */