r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[Samba/bb.git] / source / utils / net_domain.c
blob0c9b5ad571460bedc084625419c0ca0d2e3bce7c
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 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/>.
23 #include "includes.h"
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))); \
31 goto done; \
34 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
35 if (!NT_STATUS_IS_OK(result = rpc)) { \
36 DEBUG(0, debug_args); \
37 goto done; \
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,
48 DOM_SID *dom_sid )
50 struct rpc_pipe_client *pipe_hnd = NULL;
51 POLICY_HND sam_pol, domain_pol, user_pol;
52 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
53 char *acct_name;
54 uint32 flags = 0x3e8;
55 const char *const_acct_name;
56 uint32 user_rid;
57 uint32 num_rids, *name_types, *user_rids;
58 SAM_USERINFO_CTR ctr, *qctr = NULL;
59 SAM_USER_INFO_16 p16;
61 /* Open the domain */
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",
65 nt_errstr(status) ));
66 return status;
69 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
70 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
71 if ( !NT_STATUS_IS_OK(status) )
72 return 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) )
78 return 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) )
90 return 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) ) {
104 goto done;
107 /* Get user info */
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);
112 goto done;
115 /* now disable and setuser info */
117 ZERO_STRUCT(ctr);
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);
128 done:
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 */
134 return status;
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"));
145 return -1;
148 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
149 DEBUG(1,("Failed to save machine password\n"));
150 return -1;
153 return 0;
156 /*******************************************************************
157 ********************************************************************/
159 NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli,
160 char **domain, DOM_SID **sid )
162 struct rpc_pipe_client *pipe_hnd = NULL;
163 POLICY_HND lsa_pol;
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) ));
169 return 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) )
175 return 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) )
180 return 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. */
186 if (!domain) {
187 DEBUG(0, ("Could not get domain name.\n"));
188 return NT_STATUS_UNSUCCESSFUL;
191 return NT_STATUS_OK;
194 /*******************************************************************
195 Do the domain join
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;
205 char *acct_name;
206 const char *const_acct_name;
207 uint32 user_rid;
208 uint32 num_rids, *name_types, *user_rids;
209 uint32 flags = 0x3e8;
210 uint32 acb_info = ACB_WSTRUST;
211 uchar pwbuf[516];
212 SAM_USERINFO_CTR ctr;
213 SAM_USER_INFO_24 p24;
214 SAM_USER_INFO_16 p16;
215 uchar md4_trust_password[16];
217 /* Open the domain */
219 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
220 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
221 nt_errstr(status) ));
222 return status;
225 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
226 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
227 if ( !NT_STATUS_IS_OK(status) )
228 return status;
231 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
232 SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
233 if ( !NT_STATUS_IS_OK(status) )
234 return status;
236 /* Create domain user */
238 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
239 strlower_m(acct_name);
240 const_acct_name = acct_name;
242 /* Don't try to set any acb_info flags other than ACB_WSTRUST */
244 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
245 acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
247 if ( !NT_STATUS_IS_OK(status)
248 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
250 d_fprintf(stderr, "Creation of workstation account failed\n");
252 /* If NT_STATUS_ACCESS_DENIED then we have a valid
253 username/password combo but the user does not have
254 administrator access. */
256 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
257 d_fprintf(stderr, "User specified does not have administrator privileges\n");
259 return status;
262 /* We *must* do this.... don't ask... */
264 if (NT_STATUS_IS_OK(status)) {
265 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
268 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
269 &domain_pol, flags, 1, &const_acct_name,
270 &num_rids, &user_rids, &name_types);
271 if ( !NT_STATUS_IS_OK(status) )
272 return status;
274 if ( name_types[0] != SID_NAME_USER) {
275 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
276 return NT_STATUS_INVALID_WORKSTATION;
279 user_rid = user_rids[0];
281 /* Open handle on user */
283 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
284 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
286 /* Create a random machine account password */
288 E_md4hash( clear_pw, md4_trust_password);
289 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
291 /* Set password on machine account */
293 ZERO_STRUCT(ctr);
294 ZERO_STRUCT(p24);
296 init_sam_user_info24(&p24, (char *)pwbuf,24);
298 ctr.switch_value = 24;
299 ctr.info.id24 = &p24;
301 status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
302 24, &cli->user_session_key, &ctr);
304 if ( !NT_STATUS_IS_OK(status) ) {
305 d_fprintf( stderr, "Failed to set password for machine account (%s)\n",
306 nt_errstr(status));
307 return status;
311 /* Why do we have to try to (re-)set the ACB to be the same as what
312 we passed in the samr_create_dom_user() call? When a NT
313 workstation is joined to a domain by an administrator the
314 acb_info is set to 0x80. For a normal user with "Add
315 workstations to the domain" rights the acb_info is 0x84. I'm
316 not sure whether it is supposed to make a difference or not. NT
317 seems to cope with either value so don't bomb out if the set
318 userinfo2 level 0x10 fails. -tpot */
320 ZERO_STRUCT(ctr);
321 ctr.switch_value = 16;
322 ctr.info.id16 = &p16;
324 /* Fill in the additional account flags now */
326 acb_info |= ACB_PWNOEXP;
327 if ( dom_type == ND_TYPE_AD ) {
328 #if !defined(ENCTYPE_ARCFOUR_HMAC)
329 acb_info |= ACB_USE_DES_KEY_ONLY;
330 #endif
334 init_sam_user_info16(&p16, acb_info);
336 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
337 &cli->user_session_key, &ctr);
339 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
340 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
342 return status;