2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
5 Copyright (C) Tim Potter 2001
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #include "../utils/net.h"
24 /* Macro for checking RPC error codes to make things more readable */
26 #define CHECK_RPC_ERR(rpc, msg) \
27 if (!NT_STATUS_IS_OK(result = rpc)) { \
28 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
32 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
33 if (!NT_STATUS_IS_OK(result = rpc)) { \
34 DEBUG(0, debug_args); \
40 * confirm that a domain join is still valid
42 * @return A shell status integer (0 for success)
45 int net_rpc_join_ok(const char *domain
)
47 struct cli_state
*cli
;
48 uchar stored_md4_trust_password
[16];
53 /* Connect to remote machine */
54 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
| NET_FLAGS_PDC
))) {
58 if (!cli_nt_session_open(cli
, PIPE_NETLOGON
)) {
59 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
63 if (!secrets_fetch_trust_account_password(domain
,
64 stored_md4_trust_password
, NULL
)) {
65 DEBUG(0,("Could not reterive domain trust secret"));
69 if (lp_server_role() == ROLE_DOMAIN_BDC
||
70 lp_server_role() == ROLE_DOMAIN_PDC
) {
71 channel
= SEC_CHAN_BDC
;
73 channel
= SEC_CHAN_WKSTA
;
76 CHECK_RPC_ERR(cli_nt_setup_creds(cli
,
78 stored_md4_trust_password
),
79 "error in domain join verification");
81 retval
= 0; /* Success! */
84 /* Close down pipe - this will clean up open policy handles */
85 if (cli
->nt_pipe_fnum
)
86 cli_nt_session_close(cli
);
94 * Join a domain using the administrator username and password
96 * @param argc Standard main() style argc
97 * @param argc Standard main() style argv. Initial components are already
98 * stripped. Currently not used.
99 * @return A shell status integer (0 for success)
103 int net_rpc_join_newstyle(int argc
, const char **argv
)
106 extern pstring global_myname
;
108 /* libsmb variables */
110 struct cli_state
*cli
;
116 POLICY_HND lsa_pol
, sam_pol
, domain_pol
, user_pol
;
122 char *clear_trust_password
= NULL
;
123 fstring ucs2_trust_password
;
125 uchar pwbuf
[516], sess_key
[16];
126 SAM_USERINFO_CTR ctr
;
127 SAM_USER_INFO_24 p24
;
128 SAM_USER_INFO_10 p10
;
135 uint32 num_rids
, *name_types
, *user_rids
;
136 uint32 flags
= 0x3e8;
138 const char *const_acct_name
;
140 /* Connect to remote machine */
142 if (!(cli
= net_make_ipc_connection(NET_FLAGS_PDC
)))
145 if (!(mem_ctx
= talloc_init())) {
146 DEBUG(0, ("Could not initialise talloc context\n"));
150 /* Fetch domain sid */
152 if (!cli_nt_session_open(cli
, PIPE_LSARPC
)) {
153 DEBUG(0, ("Error connecting to SAM pipe\n"));
158 CHECK_RPC_ERR(cli_lsa_open_policy(cli
, mem_ctx
, True
,
159 SEC_RIGHTS_MAXIMUM_ALLOWED
,
161 "error opening lsa policy handle");
163 CHECK_RPC_ERR(cli_lsa_query_info_policy(cli
, mem_ctx
, &lsa_pol
,
164 5, domain
, &domain_sid
),
165 "error querying info policy");
167 cli_lsa_close(cli
, mem_ctx
, &lsa_pol
);
169 cli_nt_session_close(cli
); /* Done with this pipe */
171 /* Create domain user */
172 if (!cli_nt_session_open(cli
, PIPE_SAMR
)) {
173 DEBUG(0, ("Error connecting to SAM pipe\n"));
177 CHECK_RPC_ERR(cli_samr_connect(cli
, mem_ctx
,
178 SEC_RIGHTS_MAXIMUM_ALLOWED
,
180 "could not connect to SAM database");
183 CHECK_RPC_ERR(cli_samr_open_domain(cli
, mem_ctx
, &sam_pol
,
184 SEC_RIGHTS_MAXIMUM_ALLOWED
,
185 &domain_sid
, &domain_pol
),
186 "could not open domain");
188 /* Create domain user */
189 acct_name
= talloc_asprintf(mem_ctx
, "%s$", global_myname
);
191 const_acct_name
= acct_name
;
193 acb_info
= ((lp_server_role() == ROLE_DOMAIN_BDC
) || lp_server_role() == ROLE_DOMAIN_PDC
) ? ACB_SVRTRUST
: ACB_WSTRUST
;
195 result
= cli_samr_create_dom_user(cli
, mem_ctx
, &domain_pol
,
197 0xe005000b, &user_pol
,
200 if (!NT_STATUS_IS_OK(result
) &&
201 !NT_STATUS_EQUAL(result
, NT_STATUS_USER_EXISTS
)) {
202 d_printf("Create of workstation account failed\n");
204 /* If NT_STATUS_ACCESS_DENIED then we have a valid
205 username/password combo but the user does not have
206 administrator access. */
208 if (NT_STATUS_V(result
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
))
209 d_printf("User specified does not have administrator privileges\n");
214 /* We *must* do this.... don't ask... */
216 if (NT_STATUS_IS_OK(result
))
217 cli_samr_close(cli
, mem_ctx
, &user_pol
);
219 CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli
, mem_ctx
,
223 &user_rids
, &name_types
),
224 ("error looking up rid for user %s: %s\n",
225 acct_name
, nt_errstr(result
)));
227 if (name_types
[0] != SID_NAME_USER
) {
228 DEBUG(0, ("%s is not a user account\n", acct_name
));
232 user_rid
= user_rids
[0];
234 /* Open handle on user */
237 cli_samr_open_user(cli
, mem_ctx
, &domain_pol
,
238 SEC_RIGHTS_MAXIMUM_ALLOWED
,
239 user_rid
, &user_pol
),
240 ("could not re-open existing user %s: %s\n",
241 acct_name
, nt_errstr(result
)));
243 /* Create a random machine account password */
247 str
= generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
248 clear_trust_password
= strdup(str
);
251 ucs2_pw_len
= push_ucs2(NULL
, ucs2_trust_password
,
252 clear_trust_password
,
253 sizeof(ucs2_trust_password
), 0);
255 encode_pw_buffer((char *)pwbuf
, ucs2_trust_password
,
258 /* Set password on machine account */
263 init_sam_user_info24(&p24
, (char *)pwbuf
,24);
265 ctr
.switch_value
= 24;
266 ctr
.info
.id24
= &p24
;
268 /* I don't think this is quite the right place for this
269 calculation. It should be moved somewhere where the credentials
270 are calculated. )-: */
272 mdfour(sess_key
, cli
->pwd
.smb_nt_pwd
, 16);
274 CHECK_RPC_ERR(cli_samr_set_userinfo(cli
, mem_ctx
, &user_pol
, 24,
276 "error setting trust account password");
278 /* Why do we have to try to (re-)set the ACB to be the same as what
279 we passed in the samr_create_dom_user() call? When a NT
280 workstation is joined to a domain by an administrator the
281 acb_info is set to 0x80. For a normal user with "Add
282 workstations to the domain" rights the acb_info is 0x84. I'm
283 not sure whether it is supposed to make a difference or not. NT
284 seems to cope with either value so don't bomb out if the set
285 userinfo2 level 0x10 fails. -tpot */
288 ctr
.switch_value
= 0x10;
289 ctr
.info
.id10
= &p10
;
291 init_sam_user_info10(&p10
, acb_info
);
293 /* Ignoring the return value is necessary for joining a domain
294 as a normal user with "Add workstation to domain" privilege. */
296 result
= cli_samr_set_userinfo2(cli
, mem_ctx
, &user_pol
, 0x10,
299 /* Now store the secret in the secrets database */
303 if (!secrets_store_domain_sid(domain
, &domain_sid
)) {
304 DEBUG(0, ("error storing domain sid for %s\n", domain
));
308 if (!secrets_store_machine_password(clear_trust_password
)) {
309 DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain
));
312 /* Now check the whole process from top-to-bottom */
313 cli_samr_close(cli
, mem_ctx
, &user_pol
);
314 cli_nt_session_close(cli
); /* Done with this pipe */
316 retval
= net_rpc_join_ok(domain
);
319 /* Close down pipe - this will clean up open policy handles */
321 if (cli
->nt_pipe_fnum
)
322 cli_nt_session_close(cli
);
324 /* Display success or failure */
327 trust_password_delete(domain
);
328 fprintf(stderr
,"Unable to join domain %s.\n",domain
);
330 printf("Joined domain %s.\n",domain
);
335 SAFE_FREE(clear_trust_password
);
342 * check that a join is OK
344 * @return A shell status integer (0 for success)
347 int net_rpc_testjoin(int argc
, const char **argv
)
349 char *domain
= lp_workgroup();
351 domain
= smb_xstrdup(domain
);
353 /* Display success or failure */
354 if (net_rpc_join_ok(domain
) != 0) {
355 fprintf(stderr
,"Join to domain '%s' is not valid\n",domain
);
360 printf("Join to '%s' is OK\n",domain
);