[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / utils / net_domain.c
blob5b330d8765ce786b38174c1bd99f2276db17892d
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)
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.
24 #include "includes.h"
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))); \
32 goto done; \
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; \
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,
49 DOM_SID *dom_sid )
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;
62 /* Open the domain */
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;
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;
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;
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) )
91 return 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) ) {
105 goto done;
108 /* Get user info */
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;
116 /* now disable and setuser info */
118 ZERO_STRUCT(ctr);
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);
129 done:
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 */
135 return status;
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"));
146 return -1;
149 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
150 DEBUG(1,("Failed to save machine password\n"));
151 return -1;
154 return 0;
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;
164 POLICY_HND lsa_pol;
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) ));
170 return 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) )
176 return 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) )
181 return 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. */
187 if (!domain) {
188 DEBUG(0, ("Could not get domain name.\n"));
189 return NT_STATUS_UNSUCCESSFUL;
192 return NT_STATUS_OK;
195 /*******************************************************************
196 Do the domain join
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;
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 uchar pwbuf[516];
213 SAM_USERINFO_CTR ctr;
214 SAM_USER_INFO_24 p24;
215 SAM_USER_INFO_16 p16;
216 uchar md4_trust_password[16];
218 /* Open the domain */
220 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
221 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
222 nt_errstr(status) ));
223 return status;
226 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
227 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
228 if ( !NT_STATUS_IS_OK(status) )
229 return status;
232 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
233 SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
234 if ( !NT_STATUS_IS_OK(status) )
235 return status;
237 /* Create domain user */
239 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
240 strlower_m(acct_name);
241 const_acct_name = acct_name;
243 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
245 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
246 acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
248 if ( !NT_STATUS_IS_OK(status)
249 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
251 d_fprintf(stderr, "Creation of workstation account failed\n");
253 /* If NT_STATUS_ACCESS_DENIED then we have a valid
254 username/password combo but the user does not have
255 administrator access. */
257 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
258 d_fprintf(stderr, "User specified does not have administrator privileges\n");
260 return status;
263 /* We *must* do this.... don't ask... */
265 if (NT_STATUS_IS_OK(status)) {
266 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
269 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
270 &domain_pol, flags, 1, &const_acct_name,
271 &num_rids, &user_rids, &name_types);
272 if ( !NT_STATUS_IS_OK(status) )
273 return status;
275 if ( name_types[0] != SID_NAME_USER) {
276 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
277 return NT_STATUS_INVALID_WORKSTATION;
280 user_rid = user_rids[0];
282 /* Open handle on user */
284 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
285 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
287 /* Create a random machine account password */
289 E_md4hash( clear_pw, md4_trust_password);
290 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
292 /* Set password on machine account */
294 ZERO_STRUCT(ctr);
295 ZERO_STRUCT(p24);
297 init_sam_user_info24(&p24, (char *)pwbuf,24);
299 ctr.switch_value = 24;
300 ctr.info.id24 = &p24;
302 status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
303 24, &cli->user_session_key, &ctr);
305 if ( !NT_STATUS_IS_OK(status) ) {
306 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
307 nt_errstr(status));
308 return status;
312 /* Why do we have to try to (re-)set the ACB to be the same as what
313 we passed in the samr_create_dom_user() call? When a NT
314 workstation is joined to a domain by an administrator the
315 acb_info is set to 0x80. For a normal user with "Add
316 workstations to the domain" rights the acb_info is 0x84. I'm
317 not sure whether it is supposed to make a difference or not. NT
318 seems to cope with either value so don't bomb out if the set
319 userinfo2 level 0x10 fails. -tpot */
321 ZERO_STRUCT(ctr);
322 ctr.switch_value = 16;
323 ctr.info.id16 = &p16;
325 /* Fill in the additional account flags now */
327 acb_info |= ACB_PWNOEXP;
328 if ( dom_type == ND_TYPE_AD ) {
329 #if !defined(ENCTYPE_ARCFOUR_HMAC)
330 acb_info |= ACB_USE_DES_KEY_ONLY;
331 #endif
335 init_sam_user_info16(&p16, acb_info);
337 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
338 &cli->user_session_key, &ctr);
340 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
341 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
343 return status;