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 /*******************************************************************
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 *******************************************************************/
47 NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
50 struct rpc_pipe_client *pipe_hnd = NULL;
51 POLICY_HND sam_pol, domain_pol, user_pol;
52 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
55 const char *const_acct_name;
57 uint32 num_rids, *name_types, *user_rids;
58 SAM_USERINFO_CTR ctr, *qctr = 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_connect(pipe_hnd, mem_ctx,
70 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
71 if ( !NT_STATUS_IS_OK(status) )
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) )
80 /* Create domain user */
82 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
83 strlower_m(acct_name);
84 const_acct_name = acct_name;
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) )
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;
97 user_rid = user_rids[0];
99 /* Open handle on user */
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) ) {
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);
115 /* now disable and setuser info */
118 ctr.switch_value = 16;
119 ctr.info.id16 = &p16;
121 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
123 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
124 &cli->user_session_key, &ctr);
126 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
129 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
130 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
132 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
137 /*******************************************************************
138 Store the machine password and domain SID
139 ********************************************************************/
141 int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
143 if (!secrets_store_domain_sid(domain, sid)) {
144 DEBUG(1,("Failed to save domain sid\n"));
148 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
149 DEBUG(1,("Failed to save machine password\n"));
156 /*******************************************************************
157 ********************************************************************/
159 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli,
160 const char **domain, DOM_SID **sid )
162 struct rpc_pipe_client *pipe_hnd = NULL;
164 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
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) ));
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) )
177 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
178 &lsa_pol, 5, domain, sid);
179 if ( !NT_STATUS_IS_OK(status) )
182 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
183 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
185 /* Bail out if domain didn't get set. */
187 DEBUG(0, ("Could not get domain name.\n"));
188 return NT_STATUS_UNSUCCESSFUL;
194 /*******************************************************************
196 ********************************************************************/
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 )
202 struct rpc_pipe_client *pipe_hnd = NULL;
203 POLICY_HND sam_pol, domain_pol, user_pol;
204 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206 const char *const_acct_name;
208 uint32 num_rids, *name_types, *user_rids;
209 uint32 flags = 0x3e8;
210 uint32 acb_info = ACB_WSTRUST;
211 uint32 fields_present;
213 SAM_USERINFO_CTR ctr;
214 SAM_USER_INFO_25 p25;
215 const int infolevel = 25;
216 struct MD5Context md5ctx;
218 DATA_BLOB digested_session_key;
219 uchar md4_trust_password[16];
221 /* Open the domain */
223 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
224 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
225 nt_errstr(status) ));
229 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
230 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
231 if ( !NT_STATUS_IS_OK(status) )
235 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
236 SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
237 if ( !NT_STATUS_IS_OK(status) )
240 /* Create domain user */
242 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
243 strlower_m(acct_name);
244 const_acct_name = acct_name;
246 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
248 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
249 acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
251 if ( !NT_STATUS_IS_OK(status)
252 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
254 d_fprintf(stderr, "Creation of workstation account failed\n");
256 /* If NT_STATUS_ACCESS_DENIED then we have a valid
257 username/password combo but the user does not have
258 administrator access. */
260 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
261 d_fprintf(stderr, "User specified does not have administrator privileges\n");
266 /* We *must* do this.... don't ask... */
268 if (NT_STATUS_IS_OK(status)) {
269 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
272 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
273 &domain_pol, flags, 1, &const_acct_name,
274 &num_rids, &user_rids, &name_types);
275 if ( !NT_STATUS_IS_OK(status) )
278 if ( name_types[0] != SID_NAME_USER) {
279 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
280 return NT_STATUS_INVALID_WORKSTATION;
283 user_rid = user_rids[0];
285 /* Open handle on user */
287 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
288 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
289 if (!NT_STATUS_IS_OK(status)) {
293 /* Create a random machine account password and generate the hash */
295 E_md4hash(clear_pw, md4_trust_password);
296 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
298 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
299 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
302 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
303 MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
304 MD5Final(digested_session_key.data, &md5ctx);
306 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
307 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
309 /* Fill in the additional account flags now */
311 acb_info |= ACB_PWNOEXP;
312 if ( dom_type == ND_TYPE_AD ) {
313 #if !defined(ENCTYPE_ARCFOUR_HMAC)
314 acb_info |= ACB_USE_DES_KEY_ONLY;
319 /* Set password and account flags on machine account */
324 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
325 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
327 ctr.switch_value = infolevel;
328 ctr.info.id25 = &p25;
330 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
331 infolevel, &cli->user_session_key, &ctr);
333 if ( !NT_STATUS_IS_OK(status) ) {
334 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
339 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
340 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */