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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 const char *const_acct_name
;
58 uint32 num_rids
, *name_types
, *user_rids
;
59 SAM_USERINFO_CTR ctr
, *qctr
= NULL
;
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",
70 status
= rpccli_samr_connect(pipe_hnd
, mem_ctx
,
71 SEC_RIGHTS_MAXIMUM_ALLOWED
, &sam_pol
);
72 if ( !NT_STATUS_IS_OK(status
) )
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
) )
81 /* Create domain user */
83 acct_name
= talloc_asprintf(mem_ctx
, "%s$", global_myname());
84 strlower_m(acct_name
);
85 const_acct_name
= acct_name
;
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
) )
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
;
98 user_rid
= user_rids
[0];
100 /* Open handle on user */
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
) ) {
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
);
116 /* now disable and setuser info */
119 ctr
.switch_value
= 16;
120 ctr
.info
.id16
= &p16
;
122 p16
.acb_info
= qctr
->info
.id16
->acb_info
| ACB_DISABLED
;
124 status
= rpccli_samr_set_userinfo2(pipe_hnd
, mem_ctx
, &user_pol
, 16,
125 &cli
->user_session_key
, &ctr
);
127 rpccli_samr_close(pipe_hnd
, mem_ctx
, &user_pol
);
130 rpccli_samr_close(pipe_hnd
, mem_ctx
, &domain_pol
);
131 rpccli_samr_close(pipe_hnd
, mem_ctx
, &sam_pol
);
133 cli_rpc_pipe_close(pipe_hnd
); /* Done with this pipe */
138 /*******************************************************************
139 Store the machine password and domain SID
140 ********************************************************************/
142 int netdom_store_machine_account( const char *domain
, DOM_SID
*sid
, const char *pw
)
144 if (!secrets_store_domain_sid(domain
, sid
)) {
145 DEBUG(1,("Failed to save domain sid\n"));
149 if (!secrets_store_machine_password(pw
, domain
, SEC_CHAN_WKSTA
)) {
150 DEBUG(1,("Failed to save machine password\n"));
157 /*******************************************************************
158 ********************************************************************/
160 NTSTATUS
netdom_get_domain_sid( TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
161 char **domain
, DOM_SID
**sid
)
163 struct rpc_pipe_client
*pipe_hnd
= NULL
;
165 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
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
) ));
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
) )
178 status
= rpccli_lsa_query_info_policy(pipe_hnd
, mem_ctx
,
179 &lsa_pol
, 5, domain
, sid
);
180 if ( !NT_STATUS_IS_OK(status
) )
183 rpccli_lsa_Close(pipe_hnd
, mem_ctx
, &lsa_pol
);
184 cli_rpc_pipe_close(pipe_hnd
); /* Done with this pipe */
186 /* Bail out if domain didn't get set. */
188 DEBUG(0, ("Could not get domain name.\n"));
189 return NT_STATUS_UNSUCCESSFUL
;
195 /*******************************************************************
197 ********************************************************************/
199 NTSTATUS
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
)
203 struct rpc_pipe_client
*pipe_hnd
= NULL
;
204 POLICY_HND sam_pol
, domain_pol
, user_pol
;
205 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
207 const char *const_acct_name
;
209 uint32 num_rids
, *name_types
, *user_rids
;
210 uint32 flags
= 0x3e8;
211 uint32 acb_info
= ACB_WSTRUST
;
212 uint32 fields_present
;
214 SAM_USERINFO_CTR ctr
;
215 SAM_USER_INFO_25 p25
;
216 const int infolevel
= 25;
217 struct MD5Context md5ctx
;
219 DATA_BLOB digested_session_key
;
220 uchar md4_trust_password
[16];
222 /* Open the domain */
224 if ( (pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SAMR
, &status
)) == NULL
) {
225 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
226 nt_errstr(status
) ));
230 status
= rpccli_samr_connect(pipe_hnd
, mem_ctx
,
231 SEC_RIGHTS_MAXIMUM_ALLOWED
, &sam_pol
);
232 if ( !NT_STATUS_IS_OK(status
) )
236 status
= rpccli_samr_open_domain(pipe_hnd
, mem_ctx
, &sam_pol
,
237 SEC_RIGHTS_MAXIMUM_ALLOWED
, dom_sid
, &domain_pol
);
238 if ( !NT_STATUS_IS_OK(status
) )
241 /* Create domain user */
243 acct_name
= talloc_asprintf(mem_ctx
, "%s$", global_myname());
244 strlower_m(acct_name
);
245 const_acct_name
= acct_name
;
247 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
249 status
= rpccli_samr_create_dom_user(pipe_hnd
, mem_ctx
, &domain_pol
,
250 acct_name
, acb_info
, 0xe005000b, &user_pol
, &user_rid
);
252 if ( !NT_STATUS_IS_OK(status
)
253 && !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
))
255 d_fprintf(stderr
, "Creation of workstation account failed\n");
257 /* If NT_STATUS_ACCESS_DENIED then we have a valid
258 username/password combo but the user does not have
259 administrator access. */
261 if (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
))
262 d_fprintf(stderr
, "User specified does not have administrator privileges\n");
267 /* We *must* do this.... don't ask... */
269 if (NT_STATUS_IS_OK(status
)) {
270 rpccli_samr_close(pipe_hnd
, mem_ctx
, &user_pol
);
273 status
= rpccli_samr_lookup_names(pipe_hnd
, mem_ctx
,
274 &domain_pol
, flags
, 1, &const_acct_name
,
275 &num_rids
, &user_rids
, &name_types
);
276 if ( !NT_STATUS_IS_OK(status
) )
279 if ( name_types
[0] != SID_NAME_USER
) {
280 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
, name_types
[0]));
281 return NT_STATUS_INVALID_WORKSTATION
;
284 user_rid
= user_rids
[0];
286 /* Open handle on user */
288 status
= rpccli_samr_open_user(pipe_hnd
, mem_ctx
, &domain_pol
,
289 SEC_RIGHTS_MAXIMUM_ALLOWED
, user_rid
, &user_pol
);
290 if (!NT_STATUS_IS_OK(status
)) {
294 /* Create a random machine account password and generate the hash */
296 E_md4hash(clear_pw
, md4_trust_password
);
297 encode_pw_buffer(pwbuf
, clear_pw
, STR_UNICODE
);
299 generate_random_buffer((uint8
*)md5buffer
, sizeof(md5buffer
));
300 digested_session_key
= data_blob_talloc(mem_ctx
, 0, 16);
303 MD5Update(&md5ctx
, md5buffer
, sizeof(md5buffer
));
304 MD5Update(&md5ctx
, cli
->user_session_key
.data
, cli
->user_session_key
.length
);
305 MD5Final(digested_session_key
.data
, &md5ctx
);
307 SamOEMhashBlob(pwbuf
, sizeof(pwbuf
), &digested_session_key
);
308 memcpy(&pwbuf
[516], md5buffer
, sizeof(md5buffer
));
310 /* Fill in the additional account flags now */
312 acb_info
|= ACB_PWNOEXP
;
313 if ( dom_type
== ND_TYPE_AD
) {
314 #if !defined(ENCTYPE_ARCFOUR_HMAC)
315 acb_info
|= ACB_USE_DES_KEY_ONLY
;
320 /* Set password and account flags on machine account */
325 fields_present
= ACCT_NT_PWD_SET
| ACCT_LM_PWD_SET
| ACCT_FLAGS
;
326 init_sam_user_info25P(&p25
, fields_present
, acb_info
, (char *)pwbuf
);
328 ctr
.switch_value
= infolevel
;
329 ctr
.info
.id25
= &p25
;
331 status
= rpccli_samr_set_userinfo2(pipe_hnd
, mem_ctx
, &user_pol
,
332 infolevel
, &cli
->user_session_key
, &ctr
);
334 if ( !NT_STATUS_IS_OK(status
) ) {
335 d_fprintf( stderr
, "Failed to set password for machine account (%s)\n",
340 rpccli_samr_close(pipe_hnd
, mem_ctx
, &user_pol
);
341 cli_rpc_pipe_close(pipe_hnd
); /* Done with this pipe */