source: branches/samba-3.0/source/utils/net_rpc_join.c@ 134

Last change on this file since 134 was 134, checked in by Paul Smedley, 18 years ago

Update source to 3.0.29

File size: 13.6 KB
Line 
1/*
2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Copyright (C) 2001 Andrew Bartlett ([email protected])
5 Copyright (C) Tim Potter 2001
6
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.
11
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.
16
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. */
20
21#include "includes.h"
22#include "utils/net.h"
23
24/* Macro for checking RPC error codes to make things more readable */
25
26#define CHECK_RPC_ERR(rpc, msg) \
27 if (!NT_STATUS_IS_OK(result = rpc)) { \
28 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
29 goto done; \
30 }
31
32#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
33 if (!NT_STATUS_IS_OK(result = rpc)) { \
34 DEBUG(0, debug_args); \
35 goto done; \
36 }
37
38/**
39 * confirm that a domain join is still valid
40 *
41 * @return A shell status integer (0 for success)
42 *
43 **/
44int net_rpc_join_ok(const char *domain, const char *server, struct in_addr *ip )
45{
46 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
47 enum security_types sec;
48 unsigned int conn_flags = NET_FLAGS_PDC;
49 struct cli_state *cli = NULL;
50 struct rpc_pipe_client *pipe_hnd = NULL;
51 struct rpc_pipe_client *netlogon_pipe = NULL;
52 NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL;
53
54 sec = (enum security_types)lp_security();
55
56 if (sec == SEC_ADS) {
57 /* Connect to IPC$ using machine account's credentials. We don't use anonymous
58 connection here, as it may be denied by server's local policy. */
59 net_use_machine_account();
60
61 } else {
62 /* some servers (e.g. WinNT) don't accept machine-authenticated
63 smb connections */
64 conn_flags |= NET_FLAGS_ANONYMOUS;
65 }
66
67 /* Connect to remote machine */
68 if (!(cli = net_make_ipc_connection_ex(domain, server, ip, conn_flags))) {
69 return -1;
70 }
71
72 /* Setup the creds as though we're going to do schannel... */
73 netlogon_pipe = get_schannel_session_key(cli, domain, &neg_flags, &ntret);
74
75 /* We return NT_STATUS_INVALID_NETWORK_RESPONSE if the server is refusing
76 to negotiate schannel, but the creds were set up ok. That'll have to do. */
77
78 if (!netlogon_pipe) {
79 if (NT_STATUS_EQUAL(ntret, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
80 cli_shutdown(cli);
81 return 0;
82 } else {
83 DEBUG(0,("net_rpc_join_ok: failed to get schannel session "
84 "key from server %s for domain %s. Error was %s\n",
85 cli->desthost, domain, nt_errstr(ntret) ));
86 cli_shutdown(cli);
87 return -1;
88 }
89 }
90
91 /* Only do the rest of the schannel test if the client is allowed to do this. */
92 if (!lp_client_schannel()) {
93 cli_shutdown(cli);
94 /* We're good... */
95 return 0;
96 }
97
98 pipe_hnd = cli_rpc_pipe_open_schannel_with_key(cli, PI_NETLOGON,
99 PIPE_AUTH_LEVEL_PRIVACY,
100 domain, netlogon_pipe->dc, &ntret);
101
102 if (!pipe_hnd) {
103 DEBUG(0,("net_rpc_join_ok: failed to open schannel session "
104 "on netlogon pipe to server %s for domain %s. Error was %s\n",
105 cli->desthost, domain, nt_errstr(ntret) ));
106 cli_shutdown(cli);
107 return -1;
108 }
109
110 cli_shutdown(cli);
111 return 0;
112}
113
114/**
115 * Join a domain using the administrator username and password
116 *
117 * @param argc Standard main() style argc
118 * @param argc Standard main() style argv. Initial components are already
119 * stripped. Currently not used.
120 * @return A shell status integer (0 for success)
121 *
122 **/
123
124int net_rpc_join_newstyle(int argc, const char **argv)
125{
126
127 /* libsmb variables */
128
129 struct cli_state *cli;
130 TALLOC_CTX *mem_ctx;
131 uint32 acb_info = ACB_WSTRUST;
132 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
133 uint32 sec_channel_type;
134 struct rpc_pipe_client *pipe_hnd = NULL;
135
136 /* rpc variables */
137
138 POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
139 DOM_SID *domain_sid;
140 uint32 user_rid;
141
142 /* Password stuff */
143
144 char *clear_trust_password = NULL;
145 uchar pwbuf[516];
146 SAM_USERINFO_CTR ctr;
147 SAM_USER_INFO_24 p24;
148 SAM_USER_INFO_16 p16;
149 uchar md4_trust_password[16];
150
151 /* Misc */
152
153 NTSTATUS result;
154 int retval = 1;
155 char *domain = NULL;
156 uint32 num_rids, *name_types, *user_rids;
157 uint32 flags = 0x3e8;
158 char *acct_name;
159 const char *const_acct_name;
160 uint32 acct_flags=0;
161
162 /* check what type of join */
163 if (argc >= 0) {
164 sec_channel_type = get_sec_channel_type(argv[0]);
165 } else {
166 sec_channel_type = get_sec_channel_type(NULL);
167 }
168
169 switch (sec_channel_type) {
170 case SEC_CHAN_WKSTA:
171 acb_info = ACB_WSTRUST;
172 break;
173 case SEC_CHAN_BDC:
174 acb_info = ACB_SVRTRUST;
175 break;
176#if 0
177 case SEC_CHAN_DOMAIN:
178 acb_info = ACB_DOMTRUST;
179 break;
180#endif
181 }
182
183 /* Make authenticated connection to remote machine */
184
185 if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC)))
186 return 1;
187
188 if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
189 DEBUG(0, ("Could not initialise talloc context\n"));
190 goto done;
191 }
192
193 /* Fetch domain sid */
194
195 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &result);
196 if (!pipe_hnd) {
197 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
198 nt_errstr(result) ));
199 goto done;
200 }
201
202
203 CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
204 SEC_RIGHTS_MAXIMUM_ALLOWED,
205 &lsa_pol),
206 "error opening lsa policy handle");
207
208 CHECK_RPC_ERR(rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
209 5, &domain, &domain_sid),
210 "error querying info policy");
211
212 rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
213 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
214
215 /* Bail out if domain didn't get set. */
216 if (!domain) {
217 DEBUG(0, ("Could not get domain name.\n"));
218 goto done;
219 }
220
221 /* Create domain user */
222 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);
223 if (!pipe_hnd) {
224 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
225 nt_errstr(result) ));
226 goto done;
227 }
228
229 CHECK_RPC_ERR(rpccli_samr_connect(pipe_hnd, mem_ctx,
230 SEC_RIGHTS_MAXIMUM_ALLOWED,
231 &sam_pol),
232 "could not connect to SAM database");
233
234
235 CHECK_RPC_ERR(rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
236 SEC_RIGHTS_MAXIMUM_ALLOWED,
237 domain_sid, &domain_pol),
238 "could not open domain");
239
240 /* Create domain user */
241 if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) {
242 result = NT_STATUS_NO_MEMORY;
243 goto done;
244 }
245 strlower_m(acct_name);
246 const_acct_name = acct_name;
247
248 acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE |
249 SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC |
250 SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR |
251 SAMR_USER_SETATTR;
252 DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
253 result = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
254 acct_name, acb_info,
255 acct_flags, &user_pol,
256 &user_rid);
257
258 if (!NT_STATUS_IS_OK(result) &&
259 !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
260 d_fprintf(stderr, "Creation of workstation account failed\n");
261
262 /* If NT_STATUS_ACCESS_DENIED then we have a valid
263 username/password combo but the user does not have
264 administrator access. */
265
266 if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
267 d_fprintf(stderr, "User specified does not have administrator privileges\n");
268
269 goto done;
270 }
271
272 /* We *must* do this.... don't ask... */
273
274 if (NT_STATUS_IS_OK(result)) {
275 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
276 }
277
278 CHECK_RPC_ERR_DEBUG(rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
279 &domain_pol, flags,
280 1, &const_acct_name,
281 &num_rids,
282 &user_rids, &name_types),
283 ("error looking up rid for user %s: %s\n",
284 acct_name, nt_errstr(result)));
285
286 if (name_types[0] != SID_NAME_USER) {
287 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
288 goto done;
289 }
290
291 user_rid = user_rids[0];
292
293 /* Open handle on user */
294
295 CHECK_RPC_ERR_DEBUG(
296 rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
297 SEC_RIGHTS_MAXIMUM_ALLOWED,
298 user_rid, &user_pol),
299 ("could not re-open existing user %s: %s\n",
300 acct_name, nt_errstr(result)));
301
302 /* Create a random machine account password */
303
304 {
305 char *str;
306 str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
307 clear_trust_password = SMB_STRDUP(str);
308 E_md4hash(clear_trust_password, md4_trust_password);
309 }
310
311 encode_pw_buffer(pwbuf, clear_trust_password, STR_UNICODE);
312
313 /* Set password on machine account */
314
315 ZERO_STRUCT(ctr);
316 ZERO_STRUCT(p24);
317
318 init_sam_user_info24(&p24, (char *)pwbuf,24);
319
320 ctr.switch_value = 24;
321 ctr.info.id24 = &p24;
322
323 CHECK_RPC_ERR(rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol, 24,
324 &cli->user_session_key, &ctr),
325 "error setting trust account password");
326
327 /* Why do we have to try to (re-)set the ACB to be the same as what
328 we passed in the samr_create_dom_user() call? When a NT
329 workstation is joined to a domain by an administrator the
330 acb_info is set to 0x80. For a normal user with "Add
331 workstations to the domain" rights the acb_info is 0x84. I'm
332 not sure whether it is supposed to make a difference or not. NT
333 seems to cope with either value so don't bomb out if the set
334 userinfo2 level 0x10 fails. -tpot */
335
336 ZERO_STRUCT(ctr);
337 ctr.switch_value = 16;
338 ctr.info.id16 = &p16;
339
340 init_sam_user_info16(&p16, acb_info);
341
342 /* Ignoring the return value is necessary for joining a domain
343 as a normal user with "Add workstation to domain" privilege. */
344
345 result = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
346 &cli->user_session_key, &ctr);
347
348 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
349 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
350
351 /* Now check the whole process from top-to-bottom */
352
353 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, &result);
354 if (!pipe_hnd) {
355 DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n",
356 nt_errstr(result) ));
357 goto done;
358 }
359
360 result = rpccli_netlogon_setup_creds(pipe_hnd,
361 cli->desthost, /* server name */
362 domain, /* domain */
363 global_myname(), /* client name */
364 global_myname(), /* machine account name */
365 md4_trust_password,
366 sec_channel_type,
367 &neg_flags);
368
369 if (!NT_STATUS_IS_OK(result)) {
370 DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n",
371 nt_errstr(result)));
372
373 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
374 (sec_channel_type == SEC_CHAN_BDC) ) {
375 d_fprintf(stderr, "Please make sure that no computer account\n"
376 "named like this machine (%s) exists in the domain\n",
377 global_myname());
378 }
379
380 goto done;
381 }
382
383 /* We can only check the schannel connection if the client is allowed
384 to do this and the server supports it. If not, just assume success
385 (after all the rpccli_netlogon_setup_creds() succeeded, and we'll
386 do the same again (setup creds) in net_rpc_join_ok(). JRA. */
387
388 if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) {
389 struct rpc_pipe_client *netlogon_schannel_pipe =
390 cli_rpc_pipe_open_schannel_with_key(cli,
391 PI_NETLOGON,
392 PIPE_AUTH_LEVEL_PRIVACY,
393 domain,
394 pipe_hnd->dc,
395 &result);
396
397 if (!NT_STATUS_IS_OK(result)) {
398 DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n",
399 nt_errstr(result)));
400
401 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
402 (sec_channel_type == SEC_CHAN_BDC) ) {
403 d_fprintf(stderr, "Please make sure that no computer account\n"
404 "named like this machine (%s) exists in the domain\n",
405 global_myname());
406 }
407
408 goto done;
409 }
410 cli_rpc_pipe_close(netlogon_schannel_pipe);
411 }
412
413 cli_rpc_pipe_close(pipe_hnd);
414
415 /* Now store the secret in the secrets database */
416
417 strupper_m(domain);
418
419 if (!secrets_store_domain_sid(domain, domain_sid)) {
420 DEBUG(0, ("error storing domain sid for %s\n", domain));
421 goto done;
422 }
423
424 if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) {
425 DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
426 }
427
428 /* double-check, connection from scratch */
429 retval = net_rpc_join_ok(domain, cli->desthost, &cli->dest_ip);
430
431done:
432
433 /* Display success or failure */
434
435 if (domain) {
436 if (retval != 0) {
437 fprintf(stderr,"Unable to join domain %s.\n",domain);
438 } else {
439 printf("Joined domain %s.\n",domain);
440 }
441 }
442
443 cli_shutdown(cli);
444
445 SAFE_FREE(clear_trust_password);
446
447 return retval;
448}
449
450/**
451 * check that a join is OK
452 *
453 * @return A shell status integer (0 for success)
454 *
455 **/
456int net_rpc_testjoin(int argc, const char **argv)
457{
458 char *domain = smb_xstrdup(opt_target_workgroup);
459
460 /* Display success or failure */
461 if (net_rpc_join_ok(domain, NULL, NULL) != 0) {
462 fprintf(stderr,"Join to domain '%s' is not valid\n",domain);
463 free(domain);
464 return -1;
465 }
466
467 printf("Join to '%s' is OK\n",domain);
468 free(domain);
469 return 0;
470}
Note: See TracBrowser for help on using the repository browser.