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];
52 uint32 neg_flags
= 0x000001ff;
54 /* Connect to remote machine */
55 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
| NET_FLAGS_PDC
))) {
59 if (!cli_nt_session_open(cli
, PI_NETLOGON
)) {
60 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
64 if (!secrets_fetch_trust_account_password(domain
,
65 stored_md4_trust_password
, NULL
)) {
66 DEBUG(0,("Could not reterive domain trust secret"));
70 if (lp_server_role() == ROLE_DOMAIN_BDC
||
71 lp_server_role() == ROLE_DOMAIN_PDC
) {
72 channel
= SEC_CHAN_BDC
;
74 channel
= SEC_CHAN_WKSTA
;
77 CHECK_RPC_ERR(cli_nt_setup_creds(cli
,
79 stored_md4_trust_password
, &neg_flags
, 2),
80 "error in domain join verification");
82 retval
= 0; /* Success! */
85 /* Close down pipe - this will clean up open policy handles */
86 if (cli
->nt_pipe_fnum
)
87 cli_nt_session_close(cli
);
95 * Join a domain using the administrator username and password
97 * @param argc Standard main() style argc
98 * @param argc Standard main() style argv. Initial components are already
99 * stripped. Currently not used.
100 * @return A shell status integer (0 for success)
104 int net_rpc_join_newstyle(int argc
, const char **argv
)
107 /* libsmb variables */
109 struct cli_state
*cli
;
115 POLICY_HND lsa_pol
, sam_pol
, domain_pol
, user_pol
;
121 char *clear_trust_password
= NULL
;
122 fstring ucs2_trust_password
;
124 uchar pwbuf
[516], sess_key
[16];
125 SAM_USERINFO_CTR ctr
;
126 SAM_USER_INFO_24 p24
;
127 SAM_USER_INFO_10 p10
;
134 uint32 num_rids
, *name_types
, *user_rids
;
135 uint32 flags
= 0x3e8;
137 const char *const_acct_name
;
139 /* Connect to remote machine */
141 if (!(cli
= net_make_ipc_connection(NET_FLAGS_PDC
)))
144 if (!(mem_ctx
= talloc_init("net_rpc_join_newstyle"))) {
145 DEBUG(0, ("Could not initialise talloc context\n"));
149 /* Fetch domain sid */
151 if (!cli_nt_session_open(cli
, PI_LSARPC
)) {
152 DEBUG(0, ("Error connecting to SAM pipe\n"));
157 CHECK_RPC_ERR(cli_lsa_open_policy(cli
, mem_ctx
, True
,
158 SEC_RIGHTS_MAXIMUM_ALLOWED
,
160 "error opening lsa policy handle");
162 CHECK_RPC_ERR(cli_lsa_query_info_policy(cli
, mem_ctx
, &lsa_pol
,
163 5, domain
, &domain_sid
),
164 "error querying info policy");
166 cli_lsa_close(cli
, mem_ctx
, &lsa_pol
);
168 cli_nt_session_close(cli
); /* Done with this pipe */
170 /* Create domain user */
171 if (!cli_nt_session_open(cli
, PI_SAMR
)) {
172 DEBUG(0, ("Error connecting to SAM pipe\n"));
176 CHECK_RPC_ERR(cli_samr_connect(cli
, mem_ctx
,
177 SEC_RIGHTS_MAXIMUM_ALLOWED
,
179 "could not connect to SAM database");
182 CHECK_RPC_ERR(cli_samr_open_domain(cli
, mem_ctx
, &sam_pol
,
183 SEC_RIGHTS_MAXIMUM_ALLOWED
,
184 &domain_sid
, &domain_pol
),
185 "could not open domain");
187 /* Create domain user */
188 acct_name
= talloc_asprintf(mem_ctx
, "%s$", global_myname());
190 const_acct_name
= acct_name
;
192 acb_info
= ((lp_server_role() == ROLE_DOMAIN_BDC
) || lp_server_role() == ROLE_DOMAIN_PDC
) ? ACB_SVRTRUST
: ACB_WSTRUST
;
194 result
= cli_samr_create_dom_user(cli
, mem_ctx
, &domain_pol
,
196 0xe005000b, &user_pol
,
199 if (!NT_STATUS_IS_OK(result
) &&
200 !NT_STATUS_EQUAL(result
, NT_STATUS_USER_EXISTS
)) {
201 d_printf("Create of workstation account failed\n");
203 /* If NT_STATUS_ACCESS_DENIED then we have a valid
204 username/password combo but the user does not have
205 administrator access. */
207 if (NT_STATUS_V(result
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
))
208 d_printf("User specified does not have administrator privileges\n");
213 /* We *must* do this.... don't ask... */
215 if (NT_STATUS_IS_OK(result
))
216 cli_samr_close(cli
, mem_ctx
, &user_pol
);
218 CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli
, mem_ctx
,
222 &user_rids
, &name_types
),
223 ("error looking up rid for user %s: %s\n",
224 acct_name
, nt_errstr(result
)));
226 if (name_types
[0] != SID_NAME_USER
) {
227 DEBUG(0, ("%s is not a user account\n", acct_name
));
231 user_rid
= user_rids
[0];
233 /* Open handle on user */
236 cli_samr_open_user(cli
, mem_ctx
, &domain_pol
,
237 SEC_RIGHTS_MAXIMUM_ALLOWED
,
238 user_rid
, &user_pol
),
239 ("could not re-open existing user %s: %s\n",
240 acct_name
, nt_errstr(result
)));
242 /* Create a random machine account password */
246 str
= generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
247 clear_trust_password
= strdup(str
);
250 ucs2_pw_len
= push_ucs2(NULL
, ucs2_trust_password
,
251 clear_trust_password
,
252 sizeof(ucs2_trust_password
), 0);
254 encode_pw_buffer((char *)pwbuf
, ucs2_trust_password
,
257 /* Set password on machine account */
262 init_sam_user_info24(&p24
, (char *)pwbuf
,24);
264 ctr
.switch_value
= 24;
265 ctr
.info
.id24
= &p24
;
267 /* I don't think this is quite the right place for this
268 calculation. It should be moved somewhere where the credentials
269 are calculated. )-: */
271 mdfour(sess_key
, cli
->pwd
.smb_nt_pwd
, 16);
273 CHECK_RPC_ERR(cli_samr_set_userinfo(cli
, mem_ctx
, &user_pol
, 24,
275 "error setting trust account password");
277 /* Why do we have to try to (re-)set the ACB to be the same as what
278 we passed in the samr_create_dom_user() call? When a NT
279 workstation is joined to a domain by an administrator the
280 acb_info is set to 0x80. For a normal user with "Add
281 workstations to the domain" rights the acb_info is 0x84. I'm
282 not sure whether it is supposed to make a difference or not. NT
283 seems to cope with either value so don't bomb out if the set
284 userinfo2 level 0x10 fails. -tpot */
287 ctr
.switch_value
= 0x10;
288 ctr
.info
.id10
= &p10
;
290 init_sam_user_info10(&p10
, acb_info
);
292 /* Ignoring the return value is necessary for joining a domain
293 as a normal user with "Add workstation to domain" privilege. */
295 result
= cli_samr_set_userinfo2(cli
, mem_ctx
, &user_pol
, 0x10,
298 /* Now store the secret in the secrets database */
302 if (!secrets_store_domain_sid(domain
, &domain_sid
)) {
303 DEBUG(0, ("error storing domain sid for %s\n", domain
));
307 if (!secrets_store_machine_password(clear_trust_password
)) {
308 DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain
));
311 /* Now check the whole process from top-to-bottom */
312 cli_samr_close(cli
, mem_ctx
, &user_pol
);
313 cli_nt_session_close(cli
); /* Done with this pipe */
315 retval
= net_rpc_join_ok(domain
);
318 /* Close down pipe - this will clean up open policy handles */
320 if (cli
->nt_pipe_fnum
)
321 cli_nt_session_close(cli
);
323 /* Display success or failure */
326 trust_password_delete(domain
);
327 fprintf(stderr
,"Unable to join domain %s.\n",domain
);
329 printf("Joined domain %s.\n",domain
);
334 SAFE_FREE(clear_trust_password
);
341 * check that a join is OK
343 * @return A shell status integer (0 for success)
346 int net_rpc_testjoin(int argc
, const char **argv
)
348 char *domain
= smb_xstrdup(lp_workgroup());
350 /* Display success or failure */
351 if (net_rpc_join_ok(domain
) != 0) {
352 fprintf(stderr
,"Join to domain '%s' is not valid\n",domain
);
357 printf("Join to '%s' is OK\n",domain
);