Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * libnet Join Support
4 : * Copyright (C) Gerald (Jerry) Carter 2006
5 : * Copyright (C) Guenther Deschner 2007-2008
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 3 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, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "ads.h"
23 : #include "libsmb/namequery.h"
24 : #include "librpc/gen_ndr/ndr_libnet_join.h"
25 : #include "libnet/libnet_join.h"
26 : #include "libcli/auth/libcli_auth.h"
27 : #include "../librpc/gen_ndr/ndr_samr_c.h"
28 : #include "rpc_client/init_samr.h"
29 : #include "../librpc/gen_ndr/ndr_lsa_c.h"
30 : #include "rpc_client/cli_lsarpc.h"
31 : #include "../librpc/gen_ndr/ndr_netlogon.h"
32 : #include "rpc_client/cli_netlogon.h"
33 : #include "lib/smbconf/smbconf.h"
34 : #include "lib/smbconf/smbconf_reg.h"
35 : #include "../libds/common/flags.h"
36 : #include "secrets.h"
37 : #include "rpc_client/init_lsa.h"
38 : #include "rpc_client/cli_pipe.h"
39 : #include "../libcli/security/security.h"
40 : #include "passdb.h"
41 : #include "libsmb/libsmb.h"
42 : #include "../libcli/smb/smbXcli_base.h"
43 : #include "lib/param/loadparm.h"
44 : #include "libcli/auth/netlogon_creds_cli.h"
45 : #include "auth/credentials/credentials.h"
46 : #include "libsmb/dsgetdcname.h"
47 : #include "rpc_client/util_netlogon.h"
48 : #include "libnet/libnet_join_offline.h"
49 :
50 : /****************************************************************
51 : ****************************************************************/
52 :
53 : #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
54 : do { \
55 : char *str = NULL; \
56 : str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
57 : DEBUG(1,("libnet_Join:\n%s", str)); \
58 : TALLOC_FREE(str); \
59 : } while (0)
60 :
61 : #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
62 : LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
63 : #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
64 : LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
65 :
66 : #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
67 : do { \
68 : char *str = NULL; \
69 : str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
70 : DEBUG(1,("libnet_Unjoin:\n%s", str)); \
71 : TALLOC_FREE(str); \
72 : } while (0)
73 :
74 : #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
75 : LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
76 : #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
77 : LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
78 :
79 : /****************************************************************
80 : ****************************************************************/
81 :
82 : static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
83 : struct libnet_JoinCtx *r,
84 : const char *format, ...)
85 : PRINTF_ATTRIBUTE(3,4);
86 :
87 13 : static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
88 : struct libnet_JoinCtx *r,
89 : const char *format, ...)
90 : {
91 0 : va_list args;
92 :
93 13 : if (r->out.error_string) {
94 0 : return;
95 : }
96 :
97 13 : va_start(args, format);
98 13 : r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
99 13 : va_end(args);
100 : }
101 :
102 : /****************************************************************
103 : ****************************************************************/
104 :
105 : static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
106 : struct libnet_UnjoinCtx *r,
107 : const char *format, ...)
108 : PRINTF_ATTRIBUTE(3,4);
109 :
110 6 : static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
111 : struct libnet_UnjoinCtx *r,
112 : const char *format, ...)
113 : {
114 0 : va_list args;
115 :
116 6 : if (r->out.error_string) {
117 4 : return;
118 : }
119 :
120 2 : va_start(args, format);
121 2 : r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
122 2 : va_end(args);
123 : }
124 :
125 : #ifdef HAVE_ADS
126 :
127 : /****************************************************************
128 : ****************************************************************/
129 :
130 148 : static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
131 : const char *netbios_domain_name,
132 : const char *dc_name,
133 : struct cli_credentials *creds,
134 : TALLOC_CTX *mem_ctx,
135 : ADS_STRUCT **ads)
136 : {
137 148 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
138 0 : ADS_STATUS status;
139 148 : ADS_STRUCT *my_ads = NULL;
140 :
141 148 : my_ads = ads_init(tmp_ctx,
142 : dns_domain_name,
143 : netbios_domain_name,
144 : dc_name,
145 : ADS_SASL_SEAL);
146 148 : if (!my_ads) {
147 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
148 0 : goto out;
149 : }
150 :
151 148 : status = ads_connect_creds(my_ads, creds);
152 148 : if (!ADS_ERR_OK(status)) {
153 2 : goto out;
154 : }
155 :
156 146 : *ads = talloc_move(mem_ctx, &my_ads);
157 :
158 146 : status = ADS_SUCCESS;
159 148 : out:
160 148 : TALLOC_FREE(tmp_ctx);
161 148 : return status;
162 : }
163 :
164 : /****************************************************************
165 : ****************************************************************/
166 :
167 114 : static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
168 : struct libnet_JoinCtx *r,
169 : bool use_machine_creds)
170 : {
171 0 : ADS_STATUS status;
172 114 : struct cli_credentials *creds = NULL;
173 :
174 114 : if (use_machine_creds) {
175 54 : const char *username = NULL;
176 0 : NTSTATUS ntstatus;
177 :
178 54 : if (r->in.machine_name == NULL ||
179 54 : r->in.machine_password == NULL) {
180 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
181 : }
182 54 : if (r->out.dns_domain_name != NULL) {
183 54 : username = talloc_asprintf(mem_ctx, "%s$@%s",
184 : r->in.machine_name,
185 : r->out.dns_domain_name);
186 54 : if (username == NULL) {
187 0 : return ADS_ERROR(LDAP_NO_MEMORY);
188 : }
189 : } else {
190 0 : username = talloc_asprintf(mem_ctx, "%s$",
191 : r->in.machine_name);
192 0 : if (username == NULL) {
193 0 : return ADS_ERROR(LDAP_NO_MEMORY);
194 : }
195 : }
196 :
197 54 : ntstatus = ads_simple_creds(mem_ctx,
198 : r->out.netbios_domain_name,
199 : username,
200 : r->in.machine_password,
201 : &creds);
202 54 : if (!NT_STATUS_IS_OK(ntstatus)) {
203 0 : return ADS_ERROR_NT(ntstatus);
204 : }
205 : } else {
206 60 : creds = r->in.admin_credentials;
207 : }
208 :
209 114 : status = libnet_connect_ads(r->out.dns_domain_name,
210 : r->out.netbios_domain_name,
211 : r->in.dc_name,
212 : creds,
213 : r,
214 114 : &r->in.ads);
215 114 : if (!ADS_ERR_OK(status)) {
216 0 : libnet_join_set_error_string(mem_ctx, r,
217 : "failed to connect to AD: %s",
218 : ads_errstr(status));
219 0 : return status;
220 : }
221 :
222 114 : if (!r->out.netbios_domain_name) {
223 0 : r->out.netbios_domain_name = talloc_strdup(mem_ctx,
224 0 : r->in.ads->server.workgroup);
225 0 : ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
226 : }
227 :
228 114 : if (!r->out.dns_domain_name) {
229 0 : r->out.dns_domain_name = talloc_strdup(mem_ctx,
230 0 : r->in.ads->config.realm);
231 0 : ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
232 : }
233 :
234 114 : r->out.domain_is_ad = true;
235 :
236 114 : return ADS_SUCCESS;
237 : }
238 :
239 : /****************************************************************
240 : ****************************************************************/
241 :
242 60 : static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
243 : struct libnet_JoinCtx *r)
244 : {
245 60 : return libnet_join_connect_ads(mem_ctx, r, false);
246 : }
247 :
248 : /****************************************************************
249 : ****************************************************************/
250 :
251 54 : static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
252 : struct libnet_JoinCtx *r)
253 : {
254 54 : return libnet_join_connect_ads(mem_ctx, r, true);
255 : }
256 :
257 : /****************************************************************
258 : ****************************************************************/
259 :
260 34 : static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
261 : struct libnet_UnjoinCtx *r)
262 : {
263 0 : ADS_STATUS status;
264 :
265 34 : status = libnet_connect_ads(r->in.domain_name,
266 : r->in.domain_name,
267 : r->in.dc_name,
268 : r->in.admin_credentials,
269 : r,
270 34 : &r->in.ads);
271 34 : if (!ADS_ERR_OK(status)) {
272 2 : libnet_unjoin_set_error_string(mem_ctx, r,
273 : "failed to connect to AD: %s",
274 : ads_errstr(status));
275 : }
276 :
277 34 : return status;
278 : }
279 :
280 : /****************************************************************
281 : join a domain using ADS (LDAP mods)
282 : ****************************************************************/
283 :
284 60 : static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
285 : struct libnet_JoinCtx *r)
286 : {
287 0 : ADS_STATUS status;
288 60 : LDAPMessage *res = NULL;
289 60 : const char *attrs[] = { "dn", NULL };
290 60 : bool moved = false;
291 :
292 60 : status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
293 60 : if (!ADS_ERR_OK(status)) {
294 0 : return status;
295 : }
296 :
297 60 : status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
298 60 : if (!ADS_ERR_OK(status)) {
299 0 : return status;
300 : }
301 :
302 60 : if (ads_count_replies(r->in.ads, res) != 1) {
303 0 : ads_msgfree(r->in.ads, res);
304 0 : return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
305 : }
306 :
307 60 : ads_msgfree(r->in.ads, res);
308 :
309 : /* Attempt to create the machine account and bail if this fails.
310 : Assume that the admin wants exactly what they requested */
311 :
312 60 : if (r->in.machine_password == NULL) {
313 52 : r->in.machine_password =
314 52 : trust_pw_new_value(mem_ctx,
315 : r->in.secure_channel_type,
316 : SEC_ADS);
317 52 : if (r->in.machine_password == NULL) {
318 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
319 : }
320 : }
321 :
322 60 : status = ads_create_machine_acct(r->in.ads,
323 : r->in.machine_name,
324 : r->in.machine_password,
325 : r->in.account_ou,
326 : r->in.desired_encryption_types,
327 : r->out.dns_domain_name);
328 :
329 60 : if (ADS_ERR_OK(status)) {
330 60 : DBG_WARNING("Machine account successfully created\n");
331 60 : return status;
332 0 : } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
333 0 : (status.err.rc == LDAP_ALREADY_EXISTS)) {
334 0 : status = ADS_SUCCESS;
335 : }
336 :
337 0 : if (!ADS_ERR_OK(status)) {
338 0 : DBG_WARNING("Failed to create machine account\n");
339 0 : return status;
340 : }
341 :
342 0 : status = ads_move_machine_acct(r->in.ads,
343 : r->in.machine_name,
344 : r->in.account_ou,
345 : &moved);
346 0 : if (!ADS_ERR_OK(status)) {
347 0 : DEBUG(1,("failure to locate/move pre-existing "
348 : "machine account\n"));
349 0 : return status;
350 : }
351 :
352 0 : DEBUG(1,("The machine account %s the specified OU.\n",
353 : moved ? "was moved into" : "already exists in"));
354 :
355 0 : return status;
356 : }
357 :
358 : /****************************************************************
359 : ****************************************************************/
360 :
361 32 : static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
362 : struct libnet_UnjoinCtx *r)
363 : {
364 0 : ADS_STATUS status;
365 :
366 32 : if (!r->in.ads) {
367 0 : status = libnet_unjoin_connect_ads(mem_ctx, r);
368 0 : if (!ADS_ERR_OK(status)) {
369 0 : libnet_unjoin_set_error_string(mem_ctx, r,
370 : "failed to connect to AD: %s",
371 : ads_errstr(status));
372 0 : return status;
373 : }
374 : }
375 :
376 32 : status = ads_leave_realm(r->in.ads, r->in.machine_name);
377 32 : if (!ADS_ERR_OK(status)) {
378 0 : libnet_unjoin_set_error_string(mem_ctx, r,
379 : "failed to leave realm: %s",
380 : ads_errstr(status));
381 0 : return status;
382 : }
383 :
384 32 : return ADS_SUCCESS;
385 : }
386 :
387 : /****************************************************************
388 : ****************************************************************/
389 :
390 176 : static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
391 : struct libnet_JoinCtx *r)
392 : {
393 0 : ADS_STATUS status;
394 176 : LDAPMessage *res = NULL;
395 176 : char *dn = NULL;
396 0 : struct dom_sid sid;
397 :
398 176 : if (!r->in.machine_name) {
399 0 : return ADS_ERROR(LDAP_NO_MEMORY);
400 : }
401 :
402 176 : status = ads_find_machine_acct(r->in.ads,
403 : &res,
404 : r->in.machine_name);
405 176 : if (!ADS_ERR_OK(status)) {
406 0 : return status;
407 : }
408 :
409 176 : if (ads_count_replies(r->in.ads, res) != 1) {
410 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
411 0 : goto done;
412 : }
413 :
414 176 : dn = ads_get_dn(r->in.ads, mem_ctx, res);
415 176 : if (!dn) {
416 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
417 0 : goto done;
418 : }
419 :
420 176 : r->out.dn = talloc_strdup(mem_ctx, dn);
421 176 : if (!r->out.dn) {
422 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
423 0 : goto done;
424 : }
425 :
426 176 : if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
427 : &r->out.set_encryption_types)) {
428 168 : r->out.set_encryption_types = 0;
429 : }
430 :
431 176 : if (!ads_pull_sid(r->in.ads, res, "objectSid", &sid)) {
432 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
433 0 : goto done;
434 : }
435 :
436 176 : dom_sid_split_rid(mem_ctx, &sid, NULL, &r->out.account_rid);
437 176 : done:
438 176 : ads_msgfree(r->in.ads, res);
439 176 : TALLOC_FREE(dn);
440 :
441 176 : return status;
442 : }
443 :
444 60 : static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
445 : struct libnet_JoinCtx *r,
446 : char ***spn_array,
447 : size_t *num_spns)
448 : {
449 0 : ADS_STATUS status;
450 :
451 60 : if (r->in.machine_name == NULL) {
452 0 : return ADS_ERROR_SYSTEM(EINVAL);
453 : }
454 :
455 60 : status = ads_get_service_principal_names(mem_ctx,
456 60 : r->in.ads,
457 : r->in.machine_name,
458 : spn_array,
459 : num_spns);
460 :
461 60 : return status;
462 : }
463 :
464 200 : static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const char *spn,
465 : const char ***array, size_t *num)
466 : {
467 200 : bool ok = ads_element_in_array(*array, *num, spn);
468 200 : if (!ok) {
469 24 : ok = add_string_to_array(mem_ctx, spn, array, num);
470 24 : if (!ok) {
471 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
472 : }
473 : }
474 200 : return ADS_SUCCESS;
475 : }
476 :
477 : /****************************************************************
478 : Set a machines dNSHostName and servicePrincipalName attributes
479 : ****************************************************************/
480 :
481 60 : static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
482 : struct libnet_JoinCtx *r)
483 : {
484 60 : TALLOC_CTX *frame = talloc_stackframe();
485 0 : ADS_STATUS status;
486 0 : ADS_MODLIST mods;
487 0 : fstring my_fqdn;
488 0 : fstring my_alias;
489 60 : const char **spn_array = NULL;
490 60 : size_t num_spns = 0;
491 60 : char *spn = NULL;
492 60 : const char **netbios_aliases = NULL;
493 60 : const char **addl_hostnames = NULL;
494 60 : const char *dns_hostname = NULL;
495 :
496 : /* Find our DN */
497 :
498 60 : status = libnet_join_find_machine_acct(mem_ctx, r);
499 60 : if (!ADS_ERR_OK(status)) {
500 0 : goto done;
501 : }
502 :
503 60 : status = libnet_join_get_machine_spns(frame,
504 : r,
505 : discard_const_p(char **, &spn_array),
506 : &num_spns);
507 60 : if (!ADS_ERR_OK(status)) {
508 0 : DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
509 : }
510 :
511 : /* Windows only creates HOST/shortname & HOST/fqdn. */
512 :
513 60 : spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name);
514 60 : if (spn == NULL) {
515 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
516 0 : goto done;
517 : }
518 60 : if (!strupper_m(spn)) {
519 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
520 0 : goto done;
521 : }
522 :
523 60 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
524 60 : if (!ADS_ERR_OK(status)) {
525 0 : goto done;
526 : }
527 :
528 60 : if (r->in.dnshostname != NULL) {
529 10 : fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
530 : } else {
531 50 : fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
532 : lp_dnsdomain());
533 : }
534 :
535 60 : if (!strlower_m(my_fqdn)) {
536 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
537 0 : goto done;
538 : }
539 :
540 60 : spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
541 60 : if (spn == NULL) {
542 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
543 0 : goto done;
544 : }
545 :
546 60 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
547 60 : if (!ADS_ERR_OK(status)) {
548 0 : goto done;
549 : }
550 :
551 : /*
552 : * Register dns_hostname if needed, add_uniq_spn() will avoid
553 : * duplicates.
554 : */
555 60 : dns_hostname = lp_dns_hostname();
556 60 : if (dns_hostname == NULL) {
557 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
558 0 : goto done;
559 : }
560 :
561 60 : spn = talloc_asprintf(frame, "HOST/%s", dns_hostname);
562 60 : if (spn == NULL) {
563 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
564 0 : goto done;
565 : }
566 :
567 60 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
568 60 : if (!ADS_ERR_OK(status)) {
569 0 : goto done;
570 : }
571 :
572 60 : for (netbios_aliases = lp_netbios_aliases();
573 68 : netbios_aliases != NULL && *netbios_aliases != NULL;
574 8 : netbios_aliases++) {
575 : /*
576 : * Add HOST/NETBIOSNAME
577 : */
578 8 : spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases);
579 8 : if (spn == NULL) {
580 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
581 0 : goto done;
582 : }
583 8 : if (!strupper_m(spn)) {
584 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
585 0 : goto done;
586 : }
587 :
588 8 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
589 8 : if (!ADS_ERR_OK(status)) {
590 0 : goto done;
591 : }
592 :
593 : /*
594 : * Add HOST/netbiosname.domainname
595 : */
596 8 : fstr_sprintf(my_alias, "%s.%s",
597 : *netbios_aliases,
598 : lp_dnsdomain());
599 8 : if (!strlower_m(my_alias)) {
600 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
601 0 : goto done;
602 : }
603 :
604 8 : spn = talloc_asprintf(frame, "HOST/%s", my_alias);
605 8 : if (spn == NULL) {
606 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
607 0 : goto done;
608 : }
609 :
610 8 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
611 8 : if (!ADS_ERR_OK(status)) {
612 0 : goto done;
613 : }
614 : }
615 :
616 60 : for (addl_hostnames = lp_additional_dns_hostnames();
617 64 : addl_hostnames != NULL && *addl_hostnames != NULL;
618 4 : addl_hostnames++) {
619 :
620 4 : spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames);
621 4 : if (spn == NULL) {
622 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
623 0 : goto done;
624 : }
625 :
626 4 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
627 4 : if (!ADS_ERR_OK(status)) {
628 0 : goto done;
629 : }
630 : }
631 :
632 : /* make sure to NULL terminate the array */
633 60 : spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1);
634 60 : if (spn_array == NULL) {
635 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
636 0 : goto done;
637 : }
638 60 : spn_array[num_spns] = NULL;
639 :
640 60 : mods = ads_init_mods(mem_ctx);
641 60 : if (!mods) {
642 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
643 0 : goto done;
644 : }
645 :
646 : /* fields of primary importance */
647 :
648 60 : status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
649 60 : if (!ADS_ERR_OK(status)) {
650 0 : goto done;
651 : }
652 :
653 60 : status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
654 : spn_array);
655 60 : if (!ADS_ERR_OK(status)) {
656 0 : goto done;
657 : }
658 :
659 60 : addl_hostnames = lp_additional_dns_hostnames();
660 60 : if (addl_hostnames != NULL && *addl_hostnames != NULL) {
661 2 : status = ads_mod_strlist(mem_ctx, &mods,
662 : "msDS-AdditionalDnsHostName",
663 : addl_hostnames);
664 2 : if (!ADS_ERR_OK(status)) {
665 0 : goto done;
666 : }
667 : }
668 :
669 60 : status = ads_gen_mod(r->in.ads, r->out.dn, mods);
670 :
671 60 : done:
672 60 : TALLOC_FREE(frame);
673 60 : return status;
674 : }
675 :
676 : /****************************************************************
677 : ****************************************************************/
678 :
679 60 : static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
680 : struct libnet_JoinCtx *r)
681 : {
682 0 : ADS_STATUS status;
683 0 : ADS_MODLIST mods;
684 :
685 60 : if (!r->in.create_upn) {
686 58 : return ADS_SUCCESS;
687 : }
688 :
689 : /* Find our DN */
690 :
691 2 : status = libnet_join_find_machine_acct(mem_ctx, r);
692 2 : if (!ADS_ERR_OK(status)) {
693 0 : return status;
694 : }
695 :
696 2 : if (!r->in.upn) {
697 0 : const char *realm = r->out.dns_domain_name;
698 :
699 : /* in case we are about to generate a keytab during the join
700 : * make sure the default upn we create is usable with kinit -k.
701 : * gd */
702 :
703 0 : if (USE_KERBEROS_KEYTAB) {
704 0 : realm = talloc_strdup_upper(mem_ctx,
705 : r->out.dns_domain_name);
706 : }
707 :
708 0 : if (!realm) {
709 0 : return ADS_ERROR(LDAP_NO_MEMORY);
710 : }
711 :
712 0 : r->in.upn = talloc_asprintf(mem_ctx,
713 : "host/%s@%s",
714 : r->in.machine_name,
715 : realm);
716 0 : if (!r->in.upn) {
717 0 : return ADS_ERROR(LDAP_NO_MEMORY);
718 : }
719 : }
720 :
721 : /* now do the mods */
722 :
723 2 : mods = ads_init_mods(mem_ctx);
724 2 : if (!mods) {
725 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
726 : }
727 :
728 : /* fields of primary importance */
729 :
730 2 : status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
731 2 : if (!ADS_ERR_OK(status)) {
732 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
733 : }
734 :
735 2 : return ads_gen_mod(r->in.ads, r->out.dn, mods);
736 : }
737 :
738 :
739 : /****************************************************************
740 : ****************************************************************/
741 :
742 60 : static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
743 : struct libnet_JoinCtx *r)
744 : {
745 0 : ADS_STATUS status;
746 0 : ADS_MODLIST mods;
747 60 : char *os_sp = NULL;
748 :
749 60 : if (!r->in.os_name || !r->in.os_version ) {
750 60 : return ADS_SUCCESS;
751 : }
752 :
753 : /* Find our DN */
754 :
755 0 : status = libnet_join_find_machine_acct(mem_ctx, r);
756 0 : if (!ADS_ERR_OK(status)) {
757 0 : return status;
758 : }
759 :
760 : /* now do the mods */
761 :
762 0 : mods = ads_init_mods(mem_ctx);
763 0 : if (!mods) {
764 0 : return ADS_ERROR(LDAP_NO_MEMORY);
765 : }
766 :
767 0 : if (r->in.os_servicepack) {
768 : /*
769 : * if blank string then leave os_sp equal to NULL to force
770 : * attribute delete (LDAP_MOD_DELETE)
771 : */
772 0 : if (!strequal(r->in.os_servicepack,"")) {
773 0 : os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
774 : }
775 : } else {
776 0 : os_sp = talloc_asprintf(mem_ctx, "Samba %s",
777 : samba_version_string());
778 : }
779 0 : if (!os_sp && !strequal(r->in.os_servicepack,"")) {
780 0 : return ADS_ERROR(LDAP_NO_MEMORY);
781 : }
782 :
783 : /* fields of primary importance */
784 :
785 0 : status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
786 : r->in.os_name);
787 0 : if (!ADS_ERR_OK(status)) {
788 0 : return status;
789 : }
790 :
791 0 : status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
792 : r->in.os_version);
793 0 : if (!ADS_ERR_OK(status)) {
794 0 : return status;
795 : }
796 :
797 0 : status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
798 : os_sp);
799 0 : if (!ADS_ERR_OK(status)) {
800 0 : return status;
801 : }
802 :
803 0 : return ads_gen_mod(r->in.ads, r->out.dn, mods);
804 : }
805 :
806 : /****************************************************************
807 : ****************************************************************/
808 :
809 54 : static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
810 : struct libnet_JoinCtx *r)
811 : {
812 0 : ADS_STATUS status;
813 0 : ADS_MODLIST mods;
814 0 : const char *etype_list_str;
815 :
816 54 : etype_list_str = talloc_asprintf(mem_ctx, "%d",
817 : r->in.desired_encryption_types);
818 54 : if (!etype_list_str) {
819 0 : return ADS_ERROR(LDAP_NO_MEMORY);
820 : }
821 :
822 : /* Find our DN */
823 :
824 54 : status = libnet_join_find_machine_acct(mem_ctx, r);
825 54 : if (!ADS_ERR_OK(status)) {
826 0 : return status;
827 : }
828 :
829 54 : if (r->in.desired_encryption_types == r->out.set_encryption_types) {
830 0 : return ADS_SUCCESS;
831 : }
832 :
833 : /* now do the mods */
834 :
835 54 : mods = ads_init_mods(mem_ctx);
836 54 : if (!mods) {
837 0 : return ADS_ERROR(LDAP_NO_MEMORY);
838 : }
839 :
840 54 : status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
841 : etype_list_str);
842 54 : if (!ADS_ERR_OK(status)) {
843 0 : return status;
844 : }
845 :
846 54 : status = ads_gen_mod(r->in.ads, r->out.dn, mods);
847 54 : if (!ADS_ERR_OK(status)) {
848 0 : return status;
849 : }
850 :
851 54 : r->out.set_encryption_types = r->in.desired_encryption_types;
852 :
853 54 : return ADS_SUCCESS;
854 : }
855 :
856 : /****************************************************************
857 : ****************************************************************/
858 :
859 66 : static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
860 : struct libnet_JoinCtx *r)
861 : {
862 66 : if (!USE_SYSTEM_KEYTAB) {
863 66 : return true;
864 : }
865 :
866 0 : if (ads_keytab_create_default(r->in.ads) != 0) {
867 0 : return false;
868 : }
869 :
870 0 : return true;
871 : }
872 :
873 : /****************************************************************
874 : ****************************************************************/
875 :
876 60 : static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
877 : struct libnet_JoinCtx *r)
878 : {
879 0 : uint32_t domain_func;
880 0 : ADS_STATUS status;
881 60 : const char *salt = NULL;
882 60 : char *std_salt = NULL;
883 :
884 60 : status = ads_domain_func_level(r->in.ads, &domain_func);
885 60 : if (!ADS_ERR_OK(status)) {
886 0 : libnet_join_set_error_string(mem_ctx, r,
887 : "failed to determine domain functional level: %s",
888 : ads_errstr(status));
889 0 : return false;
890 : }
891 :
892 : /* go ahead and setup the default salt */
893 :
894 60 : std_salt = kerberos_standard_des_salt();
895 60 : if (!std_salt) {
896 0 : libnet_join_set_error_string(mem_ctx, r,
897 : "failed to obtain standard DES salt");
898 0 : return false;
899 : }
900 :
901 60 : salt = talloc_strdup(mem_ctx, std_salt);
902 60 : if (!salt) {
903 0 : return false;
904 : }
905 :
906 60 : SAFE_FREE(std_salt);
907 :
908 : /* if it's a Windows functional domain, we have to look for the UPN */
909 :
910 60 : if (domain_func == DS_DOMAIN_FUNCTION_2000) {
911 0 : char *upn;
912 :
913 2 : upn = ads_get_upn(r->in.ads, mem_ctx,
914 : r->in.machine_name);
915 2 : if (upn) {
916 0 : salt = talloc_strdup(mem_ctx, upn);
917 0 : if (!salt) {
918 0 : return false;
919 : }
920 : }
921 : }
922 :
923 60 : r->out.krb5_salt = salt;
924 60 : return true;
925 : }
926 :
927 : /****************************************************************
928 : ****************************************************************/
929 :
930 78 : static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
931 : struct libnet_JoinCtx *r)
932 : {
933 0 : ADS_STATUS status;
934 78 : bool need_etype_update = false;
935 :
936 78 : if (r->in.request_offline_join) {
937 : /*
938 : * When in the "request offline join" path we can no longer
939 : * modify the AD account as we are operating w/o network - gd
940 : */
941 18 : return ADS_SUCCESS;
942 : }
943 :
944 60 : if (!r->in.ads) {
945 0 : status = libnet_join_connect_ads_user(mem_ctx, r);
946 0 : if (!ADS_ERR_OK(status)) {
947 0 : return status;
948 : }
949 : }
950 :
951 60 : status = libnet_join_set_machine_spn(mem_ctx, r);
952 60 : if (!ADS_ERR_OK(status)) {
953 0 : libnet_join_set_error_string(mem_ctx, r,
954 : "Failed to set machine spn: %s\n"
955 : "Do you have sufficient permissions to create machine "
956 : "accounts?",
957 : ads_errstr(status));
958 0 : return status;
959 : }
960 :
961 60 : status = libnet_join_set_os_attributes(mem_ctx, r);
962 60 : if (!ADS_ERR_OK(status)) {
963 0 : libnet_join_set_error_string(mem_ctx, r,
964 : "failed to set machine os attributes: %s",
965 : ads_errstr(status));
966 0 : return status;
967 : }
968 :
969 60 : status = libnet_join_set_machine_upn(mem_ctx, r);
970 60 : if (!ADS_ERR_OK(status)) {
971 0 : libnet_join_set_error_string(mem_ctx, r,
972 : "failed to set machine upn: %s",
973 : ads_errstr(status));
974 0 : return status;
975 : }
976 :
977 60 : status = libnet_join_find_machine_acct(mem_ctx, r);
978 60 : if (!ADS_ERR_OK(status)) {
979 0 : return status;
980 : }
981 :
982 60 : if (r->in.desired_encryption_types != r->out.set_encryption_types) {
983 56 : uint32_t func_level = 0;
984 :
985 56 : status = ads_domain_func_level(r->in.ads, &func_level);
986 56 : if (!ADS_ERR_OK(status)) {
987 0 : libnet_join_set_error_string(mem_ctx, r,
988 : "failed to query domain controller functional level: %s",
989 : ads_errstr(status));
990 0 : return status;
991 : }
992 :
993 56 : if (func_level >= DS_DOMAIN_FUNCTION_2008) {
994 54 : need_etype_update = true;
995 : }
996 : }
997 :
998 60 : if (need_etype_update) {
999 : /*
1000 : * We need to reconnect as machine account in order
1001 : * to update msDS-SupportedEncryptionTypes reliable
1002 : */
1003 :
1004 54 : TALLOC_FREE(r->in.ads);
1005 :
1006 54 : status = libnet_join_connect_ads_machine(mem_ctx, r);
1007 54 : if (!ADS_ERR_OK(status)) {
1008 0 : libnet_join_set_error_string(mem_ctx, r,
1009 : "Failed to connect as machine account: %s",
1010 : ads_errstr(status));
1011 0 : return status;
1012 : }
1013 :
1014 54 : status = libnet_join_set_etypes(mem_ctx, r);
1015 54 : if (!ADS_ERR_OK(status)) {
1016 0 : libnet_join_set_error_string(mem_ctx, r,
1017 : "failed to set machine kerberos encryption types: %s",
1018 : ads_errstr(status));
1019 0 : return status;
1020 : }
1021 : }
1022 :
1023 60 : if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1024 0 : return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1025 : }
1026 :
1027 60 : return ADS_SUCCESS;
1028 : }
1029 :
1030 66 : static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
1031 : struct libnet_JoinCtx *r)
1032 : {
1033 66 : if (!libnet_join_create_keytab(mem_ctx, r)) {
1034 0 : libnet_join_set_error_string(mem_ctx, r,
1035 : "failed to create kerberos keytab");
1036 0 : return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1037 : }
1038 :
1039 66 : return ADS_SUCCESS;
1040 : }
1041 : #endif /* HAVE_ADS */
1042 :
1043 : /****************************************************************
1044 : Store the machine password and domain SID
1045 : ****************************************************************/
1046 :
1047 75 : static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1048 : struct libnet_JoinCtx *r)
1049 : {
1050 0 : NTSTATUS status;
1051 :
1052 75 : status = secrets_store_JoinCtx(r);
1053 75 : if (!NT_STATUS_IS_OK(status)) {
1054 0 : DBG_ERR("secrets_store_JoinCtx() failed %s\n",
1055 : nt_errstr(status));
1056 0 : return false;
1057 : }
1058 :
1059 75 : return true;
1060 : }
1061 :
1062 : /****************************************************************
1063 : Connect dc's IPC$ share
1064 : ****************************************************************/
1065 :
1066 80 : static NTSTATUS libnet_join_connect_dc_ipc(TALLOC_CTX *mem_ctx,
1067 : const char *dc,
1068 : struct cli_credentials *creds,
1069 : struct cli_state **cli)
1070 : {
1071 80 : int flags = CLI_FULL_CONNECTION_IPC;
1072 0 : NTSTATUS status;
1073 :
1074 80 : status = cli_full_connection_creds(mem_ctx,
1075 : cli,
1076 : NULL,
1077 : dc,
1078 : NULL, 0,
1079 : "IPC$", "IPC",
1080 : creds,
1081 : flags);
1082 80 : if (!NT_STATUS_IS_OK(status)) {
1083 2 : return status;
1084 : }
1085 :
1086 78 : return NT_STATUS_OK;
1087 : }
1088 :
1089 : /****************************************************************
1090 : Lookup domain dc's info
1091 : ****************************************************************/
1092 :
1093 76 : static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1094 : struct libnet_JoinCtx *r,
1095 : struct cli_state **cli)
1096 : {
1097 76 : TALLOC_CTX *frame = talloc_stackframe();
1098 76 : struct rpc_pipe_client *pipe_hnd = NULL;
1099 0 : struct policy_handle lsa_pol;
1100 0 : NTSTATUS status, result;
1101 76 : union lsa_PolicyInformation *info = NULL;
1102 76 : struct cli_credentials *creds = NULL;
1103 0 : struct dcerpc_binding_handle *b;
1104 :
1105 76 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1106 9 : creds = cli_credentials_init_anon(frame);
1107 9 : if (creds == NULL) {
1108 0 : status = NT_STATUS_NO_MEMORY;
1109 0 : goto done;
1110 : }
1111 : } else {
1112 67 : creds = r->in.admin_credentials;
1113 : }
1114 :
1115 76 : status = libnet_join_connect_dc_ipc(mem_ctx,
1116 : r->in.dc_name,
1117 : creds,
1118 : cli);
1119 76 : if (!NT_STATUS_IS_OK(status)) {
1120 0 : goto done;
1121 : }
1122 :
1123 76 : status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1124 : &pipe_hnd);
1125 76 : if (!NT_STATUS_IS_OK(status)) {
1126 0 : DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1127 : nt_errstr(status)));
1128 0 : goto done;
1129 : }
1130 :
1131 76 : b = pipe_hnd->binding_handle;
1132 :
1133 76 : status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1134 : SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1135 76 : if (!NT_STATUS_IS_OK(status)) {
1136 0 : goto done;
1137 : }
1138 :
1139 76 : status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1140 : &lsa_pol,
1141 : LSA_POLICY_INFO_DNS,
1142 : &info,
1143 : &result);
1144 76 : if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1145 60 : r->out.domain_is_ad = true;
1146 60 : r->out.netbios_domain_name = info->dns.name.string;
1147 60 : r->out.dns_domain_name = info->dns.dns_domain.string;
1148 60 : r->out.forest_name = info->dns.dns_forest.string;
1149 60 : r->out.domain_guid = info->dns.domain_guid;
1150 60 : r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1151 60 : NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1152 : }
1153 :
1154 76 : if (!NT_STATUS_IS_OK(status)) {
1155 16 : status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1156 : &lsa_pol,
1157 : LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1158 : &info,
1159 : &result);
1160 16 : if (!NT_STATUS_IS_OK(status)) {
1161 0 : goto done;
1162 : }
1163 16 : if (!NT_STATUS_IS_OK(result)) {
1164 0 : status = result;
1165 0 : goto done;
1166 : }
1167 :
1168 16 : r->out.netbios_domain_name = info->account_domain.name.string;
1169 16 : r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1170 16 : NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1171 : }
1172 :
1173 76 : dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1174 76 : TALLOC_FREE(pipe_hnd);
1175 :
1176 0 : done:
1177 76 : TALLOC_FREE(frame);
1178 76 : return status;
1179 : }
1180 :
1181 : /****************************************************************
1182 : Do the domain join unsecure
1183 : ****************************************************************/
1184 :
1185 9 : static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1186 : struct libnet_JoinCtx *r,
1187 : struct cli_state *cli)
1188 : {
1189 9 : TALLOC_CTX *frame = talloc_stackframe();
1190 9 : struct rpc_pipe_client *authenticate_pipe = NULL;
1191 9 : struct rpc_pipe_client *passwordset_pipe = NULL;
1192 0 : struct cli_credentials *cli_creds;
1193 9 : struct netlogon_creds_cli_context *netlogon_creds = NULL;
1194 9 : struct netlogon_creds_CredentialState *creds = NULL;
1195 9 : uint32_t netlogon_flags = 0;
1196 9 : size_t len = 0;
1197 0 : bool ok;
1198 9 : DATA_BLOB new_trust_blob = data_blob_null;
1199 0 : NTSTATUS status;
1200 :
1201 9 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1202 : &authenticate_pipe);
1203 9 : if (!NT_STATUS_IS_OK(status)) {
1204 0 : TALLOC_FREE(frame);
1205 0 : return status;
1206 : }
1207 :
1208 9 : if (!r->in.machine_password) {
1209 9 : int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1210 :
1211 9 : r->in.machine_password = trust_pw_new_value(mem_ctx,
1212 : r->in.secure_channel_type,
1213 : security);
1214 9 : if (r->in.machine_password == NULL) {
1215 0 : TALLOC_FREE(frame);
1216 0 : return NT_STATUS_NO_MEMORY;
1217 : }
1218 : }
1219 :
1220 9 : cli_creds = cli_credentials_init(talloc_tos());
1221 9 : if (cli_creds == NULL) {
1222 0 : TALLOC_FREE(frame);
1223 0 : return NT_STATUS_NO_MEMORY;
1224 : }
1225 :
1226 9 : cli_credentials_set_username(cli_creds, r->out.account_name,
1227 : CRED_SPECIFIED);
1228 9 : cli_credentials_set_domain(cli_creds, r->in.domain_name,
1229 : CRED_SPECIFIED);
1230 9 : cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1231 9 : cli_credentials_set_secure_channel_type(cli_creds,
1232 : r->in.secure_channel_type);
1233 :
1234 : /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1235 9 : cli_credentials_set_password(cli_creds,
1236 : r->in.passed_machine_password,
1237 : CRED_SPECIFIED);
1238 :
1239 9 : status = rpccli_create_netlogon_creds_ctx(
1240 9 : cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
1241 : frame, &netlogon_creds);
1242 9 : if (!NT_STATUS_IS_OK(status)) {
1243 0 : TALLOC_FREE(frame);
1244 0 : return status;
1245 : }
1246 :
1247 9 : status = rpccli_setup_netlogon_creds(
1248 : cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
1249 : cli_creds);
1250 9 : if (!NT_STATUS_IS_OK(status)) {
1251 7 : TALLOC_FREE(frame);
1252 7 : return status;
1253 : }
1254 :
1255 2 : status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
1256 2 : if (!NT_STATUS_IS_OK(status)) {
1257 0 : TALLOC_FREE(frame);
1258 0 : return status;
1259 : }
1260 :
1261 2 : netlogon_flags = creds->negotiate_flags;
1262 2 : TALLOC_FREE(creds);
1263 :
1264 2 : if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1265 2 : const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1266 0 : const struct sockaddr_storage *remote_sockaddr =
1267 2 : smbXcli_conn_remote_sockaddr(cli->conn);
1268 :
1269 2 : status = cli_rpc_pipe_open_schannel_with_creds(
1270 : cli,
1271 : &ndr_table_netlogon,
1272 : NCACN_NP,
1273 : netlogon_creds,
1274 : remote_name,
1275 : remote_sockaddr,
1276 : &passwordset_pipe);
1277 2 : if (!NT_STATUS_IS_OK(status)) {
1278 0 : TALLOC_FREE(frame);
1279 0 : return status;
1280 : }
1281 : } else {
1282 0 : passwordset_pipe = authenticate_pipe;
1283 : }
1284 :
1285 2 : len = strlen(r->in.machine_password);
1286 2 : ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1287 2 : r->in.machine_password, len,
1288 : &new_trust_blob.data,
1289 : &new_trust_blob.length);
1290 2 : if (!ok) {
1291 0 : status = NT_STATUS_UNMAPPABLE_CHARACTER;
1292 0 : if (errno == ENOMEM) {
1293 0 : status = NT_STATUS_NO_MEMORY;
1294 : }
1295 0 : TALLOC_FREE(frame);
1296 0 : return status;
1297 : }
1298 :
1299 2 : status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1300 2 : passwordset_pipe->binding_handle,
1301 : &new_trust_blob,
1302 : NULL); /* new_version */
1303 2 : if (!NT_STATUS_IS_OK(status)) {
1304 0 : TALLOC_FREE(frame);
1305 0 : return status;
1306 : }
1307 :
1308 2 : TALLOC_FREE(frame);
1309 2 : return NT_STATUS_OK;
1310 : }
1311 :
1312 : /****************************************************************
1313 : Do the domain join
1314 : ****************************************************************/
1315 :
1316 7 : static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1317 : struct libnet_JoinCtx *r,
1318 : struct cli_state *cli)
1319 : {
1320 7 : struct rpc_pipe_client *pipe_hnd = NULL;
1321 0 : struct policy_handle sam_pol, domain_pol, user_pol;
1322 7 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1323 0 : char *acct_name;
1324 0 : struct lsa_String lsa_acct_name;
1325 7 : uint32_t acct_flags = ACB_WSTRUST;
1326 0 : struct samr_Ids user_rids;
1327 0 : struct samr_Ids name_types;
1328 0 : union samr_UserInfo user_info;
1329 7 : struct dcerpc_binding_handle *b = NULL;
1330 7 : unsigned int old_timeout = 0;
1331 :
1332 7 : DATA_BLOB session_key = data_blob_null;
1333 0 : struct samr_CryptPassword crypt_pwd;
1334 0 : struct samr_CryptPasswordEx crypt_pwd_ex;
1335 :
1336 7 : ZERO_STRUCT(sam_pol);
1337 7 : ZERO_STRUCT(domain_pol);
1338 7 : ZERO_STRUCT(user_pol);
1339 :
1340 7 : switch (r->in.secure_channel_type) {
1341 3 : case SEC_CHAN_WKSTA:
1342 3 : acct_flags = ACB_WSTRUST;
1343 3 : break;
1344 4 : case SEC_CHAN_BDC:
1345 4 : acct_flags = ACB_SVRTRUST;
1346 4 : break;
1347 0 : default:
1348 0 : return NT_STATUS_INVALID_PARAMETER;
1349 : }
1350 :
1351 7 : if (!r->in.machine_password) {
1352 7 : int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1353 :
1354 7 : r->in.machine_password = trust_pw_new_value(mem_ctx,
1355 : r->in.secure_channel_type,
1356 : security);
1357 7 : NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1358 : }
1359 :
1360 : /* Open the domain */
1361 :
1362 7 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1363 : &pipe_hnd);
1364 7 : if (!NT_STATUS_IS_OK(status)) {
1365 0 : DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1366 : nt_errstr(status)));
1367 0 : goto done;
1368 : }
1369 :
1370 7 : b = pipe_hnd->binding_handle;
1371 :
1372 7 : status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1373 7 : if (!NT_STATUS_IS_OK(status)) {
1374 0 : DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1375 : nt_errstr(status)));
1376 0 : goto done;
1377 : }
1378 :
1379 7 : status = dcerpc_samr_Connect2(b, mem_ctx,
1380 7 : pipe_hnd->desthost,
1381 : SAMR_ACCESS_ENUM_DOMAINS
1382 : | SAMR_ACCESS_LOOKUP_DOMAIN,
1383 : &sam_pol,
1384 : &result);
1385 7 : if (!NT_STATUS_IS_OK(status)) {
1386 0 : goto done;
1387 : }
1388 7 : if (!NT_STATUS_IS_OK(result)) {
1389 0 : status = result;
1390 0 : goto done;
1391 : }
1392 :
1393 7 : status = dcerpc_samr_OpenDomain(b, mem_ctx,
1394 : &sam_pol,
1395 : SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1396 : | SAMR_DOMAIN_ACCESS_CREATE_USER
1397 : | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1398 : r->out.domain_sid,
1399 : &domain_pol,
1400 : &result);
1401 7 : if (!NT_STATUS_IS_OK(status)) {
1402 0 : goto done;
1403 : }
1404 7 : if (!NT_STATUS_IS_OK(result)) {
1405 0 : status = result;
1406 0 : goto done;
1407 : }
1408 :
1409 : /* Create domain user */
1410 :
1411 7 : acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1412 7 : if (!strlower_m(acct_name)) {
1413 0 : status = NT_STATUS_INVALID_PARAMETER;
1414 0 : goto done;
1415 : }
1416 :
1417 7 : init_lsa_String(&lsa_acct_name, acct_name);
1418 :
1419 7 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1420 7 : uint32_t access_desired =
1421 : SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1422 : SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1423 : SAMR_USER_ACCESS_SET_PASSWORD |
1424 : SAMR_USER_ACCESS_GET_ATTRIBUTES |
1425 : SAMR_USER_ACCESS_SET_ATTRIBUTES;
1426 7 : uint32_t access_granted = 0;
1427 :
1428 7 : DEBUG(10,("Creating account with desired access mask: %d\n",
1429 : access_desired));
1430 :
1431 7 : status = dcerpc_samr_CreateUser2(b, mem_ctx,
1432 : &domain_pol,
1433 : &lsa_acct_name,
1434 : acct_flags,
1435 : access_desired,
1436 : &user_pol,
1437 : &access_granted,
1438 : &r->out.account_rid,
1439 : &result);
1440 7 : if (!NT_STATUS_IS_OK(status)) {
1441 0 : goto done;
1442 : }
1443 :
1444 7 : status = result;
1445 7 : if (!NT_STATUS_IS_OK(status) &&
1446 2 : !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1447 :
1448 0 : DEBUG(10,("Creation of workstation account failed: %s\n",
1449 : nt_errstr(status)));
1450 :
1451 : /* If NT_STATUS_ACCESS_DENIED then we have a valid
1452 : username/password combo but the user does not have
1453 : administrator access. */
1454 :
1455 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1456 0 : libnet_join_set_error_string(mem_ctx, r,
1457 : "User specified does not have "
1458 : "administrator privileges");
1459 : }
1460 :
1461 0 : goto done;
1462 : }
1463 :
1464 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1465 2 : if (!(r->in.join_flags &
1466 : WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1467 0 : goto done;
1468 : }
1469 : }
1470 :
1471 : /* We *must* do this.... don't ask... */
1472 :
1473 7 : if (NT_STATUS_IS_OK(status)) {
1474 5 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1475 : }
1476 : }
1477 :
1478 7 : status = dcerpc_samr_LookupNames(b, mem_ctx,
1479 : &domain_pol,
1480 : 1,
1481 : &lsa_acct_name,
1482 : &user_rids,
1483 : &name_types,
1484 : &result);
1485 7 : if (!NT_STATUS_IS_OK(status)) {
1486 0 : goto done;
1487 : }
1488 7 : if (!NT_STATUS_IS_OK(result)) {
1489 0 : status = result;
1490 0 : goto done;
1491 : }
1492 7 : if (user_rids.count != 1) {
1493 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1494 0 : goto done;
1495 : }
1496 7 : if (name_types.count != 1) {
1497 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1498 0 : goto done;
1499 : }
1500 :
1501 7 : if (name_types.ids[0] != SID_NAME_USER) {
1502 0 : DEBUG(0,("%s is not a user account (type=%d)\n",
1503 : acct_name, name_types.ids[0]));
1504 0 : status = NT_STATUS_INVALID_WORKSTATION;
1505 0 : goto done;
1506 : }
1507 :
1508 7 : r->out.account_rid = user_rids.ids[0];
1509 :
1510 : /* Open handle on user */
1511 :
1512 7 : status = dcerpc_samr_OpenUser(b, mem_ctx,
1513 : &domain_pol,
1514 : SEC_FLAG_MAXIMUM_ALLOWED,
1515 : r->out.account_rid,
1516 : &user_pol,
1517 : &result);
1518 7 : if (!NT_STATUS_IS_OK(status)) {
1519 0 : goto done;
1520 : }
1521 7 : if (!NT_STATUS_IS_OK(result)) {
1522 0 : status = result;
1523 0 : goto done;
1524 : }
1525 :
1526 : /* Fill in the additional account flags now */
1527 :
1528 7 : acct_flags |= ACB_PWNOEXP;
1529 :
1530 : /* Set account flags on machine account */
1531 7 : ZERO_STRUCT(user_info.info16);
1532 7 : user_info.info16.acct_flags = acct_flags;
1533 :
1534 7 : status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1535 : &user_pol,
1536 : UserControlInformation,
1537 : &user_info,
1538 : &result);
1539 7 : if (!NT_STATUS_IS_OK(status)) {
1540 0 : dcerpc_samr_DeleteUser(b, mem_ctx,
1541 : &user_pol,
1542 : &result);
1543 :
1544 0 : libnet_join_set_error_string(mem_ctx, r,
1545 : "Failed to set account flags for machine account (%s)\n",
1546 : nt_errstr(status));
1547 0 : goto done;
1548 : }
1549 :
1550 7 : if (!NT_STATUS_IS_OK(result)) {
1551 0 : status = result;
1552 :
1553 0 : dcerpc_samr_DeleteUser(b, mem_ctx,
1554 : &user_pol,
1555 : &result);
1556 :
1557 0 : libnet_join_set_error_string(mem_ctx, r,
1558 : "Failed to set account flags for machine account (%s)\n",
1559 : nt_errstr(status));
1560 0 : goto done;
1561 : }
1562 :
1563 : /* Set password on machine account - first try level 26 */
1564 :
1565 : /*
1566 : * increase the timeout as password filter modules on the DC
1567 : * might delay the operation for a significant amount of time
1568 : */
1569 7 : old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1570 :
1571 7 : status = init_samr_CryptPasswordEx(r->in.machine_password,
1572 : &session_key,
1573 : &crypt_pwd_ex);
1574 7 : if (!NT_STATUS_IS_OK(status)) {
1575 0 : goto error;
1576 : }
1577 :
1578 7 : user_info.info26.password = crypt_pwd_ex;
1579 7 : user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1580 :
1581 7 : status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1582 : &user_pol,
1583 : UserInternal5InformationNew,
1584 : &user_info,
1585 : &result);
1586 :
1587 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1588 :
1589 : /* retry with level 24 */
1590 :
1591 0 : status = init_samr_CryptPassword(r->in.machine_password,
1592 : &session_key,
1593 : &crypt_pwd);
1594 0 : if (!NT_STATUS_IS_OK(status)) {
1595 0 : goto error;
1596 : }
1597 :
1598 0 : user_info.info24.password = crypt_pwd;
1599 0 : user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1600 :
1601 0 : status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1602 : &user_pol,
1603 : UserInternal5Information,
1604 : &user_info,
1605 : &result);
1606 : }
1607 :
1608 7 : error:
1609 7 : old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1610 :
1611 7 : if (!NT_STATUS_IS_OK(status)) {
1612 :
1613 0 : dcerpc_samr_DeleteUser(b, mem_ctx,
1614 : &user_pol,
1615 : &result);
1616 :
1617 0 : libnet_join_set_error_string(mem_ctx, r,
1618 : "Failed to set password for machine account (%s)\n",
1619 : nt_errstr(status));
1620 0 : goto done;
1621 : }
1622 7 : if (!NT_STATUS_IS_OK(result)) {
1623 0 : status = result;
1624 :
1625 0 : dcerpc_samr_DeleteUser(b, mem_ctx,
1626 : &user_pol,
1627 : &result);
1628 :
1629 0 : libnet_join_set_error_string(mem_ctx, r,
1630 : "Failed to set password for machine account (%s)\n",
1631 : nt_errstr(status));
1632 0 : goto done;
1633 : }
1634 :
1635 7 : status = NT_STATUS_OK;
1636 :
1637 7 : done:
1638 7 : if (!pipe_hnd) {
1639 0 : return status;
1640 : }
1641 :
1642 7 : data_blob_clear_free(&session_key);
1643 :
1644 7 : if (is_valid_policy_hnd(&sam_pol)) {
1645 7 : dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1646 : }
1647 7 : if (is_valid_policy_hnd(&domain_pol)) {
1648 7 : dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1649 : }
1650 7 : if (is_valid_policy_hnd(&user_pol)) {
1651 7 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1652 : }
1653 7 : TALLOC_FREE(pipe_hnd);
1654 :
1655 7 : return status;
1656 : }
1657 :
1658 : /****************************************************************
1659 : ****************************************************************/
1660 :
1661 81 : NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1662 : const char *netbios_domain_name,
1663 : const char *dc_name,
1664 : enum credentials_use_kerberos kerberos_state)
1665 : {
1666 81 : TALLOC_CTX *frame = talloc_stackframe();
1667 81 : struct cli_state *cli = NULL;
1668 81 : struct rpc_pipe_client *netlogon_pipe = NULL;
1669 81 : struct cli_credentials *cli_creds = NULL;
1670 81 : struct netlogon_creds_cli_context *netlogon_creds = NULL;
1671 81 : struct netlogon_creds_CredentialState *creds = NULL;
1672 81 : uint32_t netlogon_flags = 0;
1673 0 : NTSTATUS status;
1674 81 : int flags = CLI_FULL_CONNECTION_IPC;
1675 81 : const char *remote_name = NULL;
1676 81 : const struct sockaddr_storage *remote_sockaddr = NULL;
1677 :
1678 81 : if (!dc_name) {
1679 0 : TALLOC_FREE(frame);
1680 0 : return NT_STATUS_INVALID_PARAMETER;
1681 : }
1682 :
1683 81 : if (!secrets_init()) {
1684 0 : TALLOC_FREE(frame);
1685 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1686 : }
1687 :
1688 81 : status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1689 : frame, &cli_creds);
1690 81 : if (!NT_STATUS_IS_OK(status)) {
1691 0 : TALLOC_FREE(frame);
1692 0 : return status;
1693 : }
1694 :
1695 : /* we don't want any old password */
1696 81 : cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1697 :
1698 81 : cli_credentials_set_kerberos_state(cli_creds,
1699 : kerberos_state,
1700 : CRED_SPECIFIED);
1701 :
1702 81 : status = cli_full_connection_creds(frame,
1703 : &cli,
1704 : NULL,
1705 : dc_name,
1706 : NULL, 0,
1707 : "IPC$", "IPC",
1708 : cli_creds,
1709 : flags);
1710 :
1711 81 : if (!NT_STATUS_IS_OK(status)) {
1712 0 : struct cli_credentials *anon_creds = NULL;
1713 :
1714 0 : anon_creds = cli_credentials_init_anon(frame);
1715 0 : if (anon_creds == NULL) {
1716 0 : TALLOC_FREE(frame);
1717 0 : return NT_STATUS_NO_MEMORY;
1718 : }
1719 :
1720 0 : status = cli_full_connection_creds(frame,
1721 : &cli,
1722 : NULL,
1723 : dc_name,
1724 : NULL, 0,
1725 : "IPC$", "IPC",
1726 : anon_creds,
1727 : flags);
1728 : }
1729 :
1730 81 : if (!NT_STATUS_IS_OK(status)) {
1731 0 : TALLOC_FREE(frame);
1732 0 : return status;
1733 : }
1734 :
1735 81 : status = rpccli_create_netlogon_creds_ctx(cli_creds,
1736 : dc_name,
1737 : msg_ctx,
1738 : frame,
1739 : &netlogon_creds);
1740 81 : if (!NT_STATUS_IS_OK(status)) {
1741 0 : cli_shutdown(cli);
1742 0 : TALLOC_FREE(frame);
1743 0 : return status;
1744 : }
1745 :
1746 81 : status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1747 : netlogon_creds,
1748 : true, /* force_reauth */
1749 : cli_creds);
1750 81 : if (!NT_STATUS_IS_OK(status)) {
1751 0 : DEBUG(0,("connect_to_domain_password_server: "
1752 : "unable to open the domain client session to "
1753 : "machine %s. Flags[0x%08X] Error was : %s.\n",
1754 : dc_name, (unsigned)netlogon_flags,
1755 : nt_errstr(status)));
1756 0 : cli_shutdown(cli);
1757 0 : TALLOC_FREE(frame);
1758 0 : return status;
1759 : }
1760 :
1761 81 : status = netlogon_creds_cli_get(netlogon_creds,
1762 : talloc_tos(),
1763 : &creds);
1764 81 : if (!NT_STATUS_IS_OK(status)) {
1765 0 : cli_shutdown(cli);
1766 0 : TALLOC_FREE(frame);
1767 0 : return status;
1768 : }
1769 81 : netlogon_flags = creds->negotiate_flags;
1770 81 : TALLOC_FREE(creds);
1771 :
1772 81 : if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1773 0 : cli_shutdown(cli);
1774 0 : TALLOC_FREE(frame);
1775 0 : return NT_STATUS_OK;
1776 : }
1777 :
1778 81 : remote_name = smbXcli_conn_remote_name(cli->conn);
1779 81 : remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
1780 :
1781 81 : status = cli_rpc_pipe_open_schannel_with_creds(
1782 : cli, &ndr_table_netlogon, NCACN_NP,
1783 : netlogon_creds,
1784 : remote_name,
1785 : remote_sockaddr,
1786 : &netlogon_pipe);
1787 :
1788 81 : TALLOC_FREE(netlogon_pipe);
1789 :
1790 81 : if (!NT_STATUS_IS_OK(status)) {
1791 0 : DEBUG(0,("libnet_join_ok: failed to open schannel session "
1792 : "on netlogon pipe to server %s for domain %s. "
1793 : "Error was %s\n",
1794 : remote_name,
1795 : netbios_domain_name, nt_errstr(status)));
1796 0 : cli_shutdown(cli);
1797 0 : TALLOC_FREE(frame);
1798 0 : return status;
1799 : }
1800 :
1801 81 : cli_shutdown(cli);
1802 81 : TALLOC_FREE(frame);
1803 81 : return NT_STATUS_OK;
1804 : }
1805 :
1806 : /****************************************************************
1807 : ****************************************************************/
1808 :
1809 57 : static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1810 : struct libnet_JoinCtx *r)
1811 : {
1812 0 : NTSTATUS status;
1813 57 : enum credentials_use_kerberos kerberos_state = CRED_USE_KERBEROS_DESIRED;
1814 :
1815 57 : if (r->in.admin_credentials != NULL) {
1816 55 : kerberos_state = cli_credentials_get_kerberos_state(
1817 : r->in.admin_credentials);
1818 : }
1819 :
1820 57 : status = libnet_join_ok(r->in.msg_ctx,
1821 : r->out.netbios_domain_name,
1822 : r->in.dc_name,
1823 : kerberos_state);
1824 57 : if (!NT_STATUS_IS_OK(status)) {
1825 0 : libnet_join_set_error_string(mem_ctx, r,
1826 : "failed to verify domain membership after joining: %s",
1827 : get_friendly_nt_error_msg(status));
1828 0 : return WERR_NERR_SETUPNOTJOINED;
1829 : }
1830 :
1831 57 : return WERR_OK;
1832 : }
1833 :
1834 : /****************************************************************
1835 : ****************************************************************/
1836 :
1837 34 : static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1838 : struct libnet_UnjoinCtx *r)
1839 : {
1840 : /*
1841 : * TODO: use values from 'struct libnet_UnjoinCtx' ?
1842 : */
1843 34 : return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1844 : }
1845 :
1846 : /****************************************************************
1847 : ****************************************************************/
1848 :
1849 4 : static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1850 : struct libnet_UnjoinCtx *r)
1851 : {
1852 4 : struct cli_state *cli = NULL;
1853 4 : struct rpc_pipe_client *pipe_hnd = NULL;
1854 0 : struct policy_handle sam_pol, domain_pol, user_pol;
1855 4 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1856 0 : char *acct_name;
1857 0 : uint32_t user_rid;
1858 0 : struct lsa_String lsa_acct_name;
1859 0 : struct samr_Ids user_rids;
1860 0 : struct samr_Ids name_types;
1861 4 : union samr_UserInfo *info = NULL;
1862 4 : struct dcerpc_binding_handle *b = NULL;
1863 :
1864 4 : ZERO_STRUCT(sam_pol);
1865 4 : ZERO_STRUCT(domain_pol);
1866 4 : ZERO_STRUCT(user_pol);
1867 :
1868 4 : status = libnet_join_connect_dc_ipc(mem_ctx,
1869 : r->in.dc_name,
1870 : r->in.admin_credentials,
1871 : &cli);
1872 4 : if (!NT_STATUS_IS_OK(status)) {
1873 2 : goto done;
1874 : }
1875 :
1876 : /* Open the domain */
1877 :
1878 2 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1879 : &pipe_hnd);
1880 2 : if (!NT_STATUS_IS_OK(status)) {
1881 0 : DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1882 : nt_errstr(status)));
1883 0 : goto done;
1884 : }
1885 :
1886 2 : b = pipe_hnd->binding_handle;
1887 :
1888 2 : status = dcerpc_samr_Connect2(b, mem_ctx,
1889 2 : pipe_hnd->desthost,
1890 : SEC_FLAG_MAXIMUM_ALLOWED,
1891 : &sam_pol,
1892 : &result);
1893 2 : if (!NT_STATUS_IS_OK(status)) {
1894 0 : goto done;
1895 : }
1896 2 : if (!NT_STATUS_IS_OK(result)) {
1897 0 : status = result;
1898 0 : goto done;
1899 : }
1900 :
1901 2 : status = dcerpc_samr_OpenDomain(b, mem_ctx,
1902 : &sam_pol,
1903 : SEC_FLAG_MAXIMUM_ALLOWED,
1904 : r->in.domain_sid,
1905 : &domain_pol,
1906 : &result);
1907 2 : if (!NT_STATUS_IS_OK(status)) {
1908 0 : goto done;
1909 : }
1910 2 : if (!NT_STATUS_IS_OK(result)) {
1911 0 : status = result;
1912 0 : goto done;
1913 : }
1914 :
1915 : /* Create domain user */
1916 :
1917 2 : acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1918 2 : if (!strlower_m(acct_name)) {
1919 0 : status = NT_STATUS_INVALID_PARAMETER;
1920 0 : goto done;
1921 : }
1922 :
1923 2 : init_lsa_String(&lsa_acct_name, acct_name);
1924 :
1925 2 : status = dcerpc_samr_LookupNames(b, mem_ctx,
1926 : &domain_pol,
1927 : 1,
1928 : &lsa_acct_name,
1929 : &user_rids,
1930 : &name_types,
1931 : &result);
1932 :
1933 2 : if (!NT_STATUS_IS_OK(status)) {
1934 0 : goto done;
1935 : }
1936 2 : if (!NT_STATUS_IS_OK(result)) {
1937 0 : status = result;
1938 0 : goto done;
1939 : }
1940 2 : if (user_rids.count != 1) {
1941 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1942 0 : goto done;
1943 : }
1944 2 : if (name_types.count != 1) {
1945 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1946 0 : goto done;
1947 : }
1948 :
1949 2 : if (name_types.ids[0] != SID_NAME_USER) {
1950 0 : DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1951 : name_types.ids[0]));
1952 0 : status = NT_STATUS_INVALID_WORKSTATION;
1953 0 : goto done;
1954 : }
1955 :
1956 2 : user_rid = user_rids.ids[0];
1957 :
1958 : /* Open handle on user */
1959 :
1960 2 : status = dcerpc_samr_OpenUser(b, mem_ctx,
1961 : &domain_pol,
1962 : SEC_FLAG_MAXIMUM_ALLOWED,
1963 : user_rid,
1964 : &user_pol,
1965 : &result);
1966 2 : if (!NT_STATUS_IS_OK(status)) {
1967 0 : goto done;
1968 : }
1969 2 : if (!NT_STATUS_IS_OK(result)) {
1970 0 : status = result;
1971 0 : goto done;
1972 : }
1973 :
1974 : /* Get user info */
1975 :
1976 2 : status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1977 : &user_pol,
1978 : 16,
1979 : &info,
1980 : &result);
1981 2 : if (!NT_STATUS_IS_OK(status)) {
1982 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1983 0 : goto done;
1984 : }
1985 2 : if (!NT_STATUS_IS_OK(result)) {
1986 0 : status = result;
1987 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1988 0 : goto done;
1989 : }
1990 :
1991 : /* now disable and setuser info */
1992 :
1993 2 : info->info16.acct_flags |= ACB_DISABLED;
1994 :
1995 2 : status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1996 : &user_pol,
1997 : 16,
1998 : info,
1999 : &result);
2000 2 : if (!NT_STATUS_IS_OK(status)) {
2001 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2002 0 : goto done;
2003 : }
2004 2 : if (!NT_STATUS_IS_OK(result)) {
2005 0 : status = result;
2006 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2007 0 : goto done;
2008 : }
2009 2 : status = result;
2010 2 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2011 :
2012 4 : done:
2013 4 : if (pipe_hnd && b) {
2014 2 : if (is_valid_policy_hnd(&domain_pol)) {
2015 2 : dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
2016 : }
2017 2 : if (is_valid_policy_hnd(&sam_pol)) {
2018 2 : dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
2019 : }
2020 2 : TALLOC_FREE(pipe_hnd);
2021 : }
2022 :
2023 4 : if (cli) {
2024 2 : cli_shutdown(cli);
2025 : }
2026 :
2027 4 : return status;
2028 : }
2029 :
2030 : /****************************************************************
2031 : ****************************************************************/
2032 :
2033 0 : static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
2034 : {
2035 0 : WERROR werr = WERR_OK;
2036 0 : sbcErr err;
2037 0 : struct smbconf_ctx *ctx;
2038 :
2039 0 : err = smbconf_init_reg(r, &ctx, NULL);
2040 0 : if (!SBC_ERROR_IS_OK(err)) {
2041 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2042 0 : goto done;
2043 : }
2044 :
2045 0 : err = smbconf_set_global_parameter(ctx, "netbios name",
2046 : r->in.machine_name);
2047 0 : if (!SBC_ERROR_IS_OK(err)) {
2048 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2049 0 : goto done;
2050 : }
2051 :
2052 0 : if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2053 :
2054 0 : err = smbconf_set_global_parameter(ctx, "security", "user");
2055 0 : if (!SBC_ERROR_IS_OK(err)) {
2056 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2057 0 : goto done;
2058 : }
2059 :
2060 0 : err = smbconf_set_global_parameter(ctx, "workgroup",
2061 : r->in.domain_name);
2062 0 : if (!SBC_ERROR_IS_OK(err)) {
2063 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2064 0 : goto done;
2065 : }
2066 :
2067 0 : smbconf_delete_global_parameter(ctx, "realm");
2068 0 : goto done;
2069 : }
2070 :
2071 0 : err = smbconf_set_global_parameter(ctx, "security", "domain");
2072 0 : if (!SBC_ERROR_IS_OK(err)) {
2073 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2074 0 : goto done;
2075 : }
2076 :
2077 0 : err = smbconf_set_global_parameter(ctx, "workgroup",
2078 : r->out.netbios_domain_name);
2079 0 : if (!SBC_ERROR_IS_OK(err)) {
2080 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2081 0 : goto done;
2082 : }
2083 :
2084 0 : if (r->out.domain_is_ad) {
2085 0 : err = smbconf_set_global_parameter(ctx, "security", "ads");
2086 0 : if (!SBC_ERROR_IS_OK(err)) {
2087 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2088 0 : goto done;
2089 : }
2090 :
2091 0 : err = smbconf_set_global_parameter(ctx, "realm",
2092 : r->out.dns_domain_name);
2093 0 : if (!SBC_ERROR_IS_OK(err)) {
2094 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2095 0 : goto done;
2096 : }
2097 : }
2098 :
2099 0 : done:
2100 0 : smbconf_shutdown(ctx);
2101 0 : return werr;
2102 : }
2103 :
2104 : /****************************************************************
2105 : ****************************************************************/
2106 :
2107 0 : static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
2108 : {
2109 0 : WERROR werr = WERR_OK;
2110 0 : sbcErr err;
2111 0 : struct smbconf_ctx *ctx;
2112 :
2113 0 : err = smbconf_init_reg(r, &ctx, NULL);
2114 0 : if (!SBC_ERROR_IS_OK(err)) {
2115 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2116 0 : goto done;
2117 : }
2118 :
2119 0 : if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2120 :
2121 0 : err = smbconf_set_global_parameter(ctx, "security", "user");
2122 0 : if (!SBC_ERROR_IS_OK(err)) {
2123 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2124 0 : goto done;
2125 : }
2126 :
2127 0 : err = smbconf_delete_global_parameter(ctx, "workgroup");
2128 0 : if (!SBC_ERROR_IS_OK(err)) {
2129 0 : werr = WERR_SERVICE_DOES_NOT_EXIST;
2130 0 : goto done;
2131 : }
2132 :
2133 0 : smbconf_delete_global_parameter(ctx, "realm");
2134 : }
2135 :
2136 0 : done:
2137 0 : smbconf_shutdown(ctx);
2138 0 : return werr;
2139 : }
2140 :
2141 : /****************************************************************
2142 : ****************************************************************/
2143 :
2144 75 : static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2145 : {
2146 0 : WERROR werr;
2147 :
2148 75 : if (!W_ERROR_IS_OK(r->out.result)) {
2149 0 : return r->out.result;
2150 : }
2151 :
2152 75 : if (!r->in.modify_config) {
2153 75 : return WERR_OK;
2154 : }
2155 :
2156 0 : werr = do_join_modify_vals_config(r);
2157 0 : if (!W_ERROR_IS_OK(werr)) {
2158 0 : return werr;
2159 : }
2160 :
2161 0 : lp_load_global(get_dyn_CONFIGFILE());
2162 :
2163 0 : r->out.modified_config = true;
2164 0 : r->out.result = werr;
2165 :
2166 0 : return werr;
2167 : }
2168 :
2169 : /****************************************************************
2170 : ****************************************************************/
2171 :
2172 36 : static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2173 : {
2174 0 : WERROR werr;
2175 :
2176 36 : if (!W_ERROR_IS_OK(r->out.result)) {
2177 0 : return r->out.result;
2178 : }
2179 :
2180 36 : if (!r->in.modify_config) {
2181 36 : return WERR_OK;
2182 : }
2183 :
2184 0 : werr = do_unjoin_modify_vals_config(r);
2185 0 : if (!W_ERROR_IS_OK(werr)) {
2186 0 : return werr;
2187 : }
2188 :
2189 0 : lp_load_global(get_dyn_CONFIGFILE());
2190 :
2191 0 : r->out.modified_config = true;
2192 0 : r->out.result = werr;
2193 :
2194 0 : return werr;
2195 : }
2196 :
2197 : /****************************************************************
2198 : ****************************************************************/
2199 :
2200 136 : static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2201 : const char *domain_str,
2202 : const char **domain_p,
2203 : const char **dc_p)
2204 : {
2205 136 : char *domain = NULL;
2206 136 : char *dc = NULL;
2207 136 : const char *p = NULL;
2208 :
2209 136 : if (!domain_str || !domain_p || !dc_p) {
2210 0 : return false;
2211 : }
2212 :
2213 136 : p = strchr_m(domain_str, '\\');
2214 :
2215 136 : if (p != NULL) {
2216 0 : domain = talloc_strndup(mem_ctx, domain_str,
2217 0 : PTR_DIFF(p, domain_str));
2218 0 : dc = talloc_strdup(mem_ctx, p+1);
2219 0 : if (!dc) {
2220 0 : return false;
2221 : }
2222 : } else {
2223 136 : domain = talloc_strdup(mem_ctx, domain_str);
2224 136 : dc = NULL;
2225 : }
2226 136 : if (!domain) {
2227 0 : return false;
2228 : }
2229 :
2230 136 : *domain_p = domain;
2231 :
2232 136 : if (!*dc_p && dc) {
2233 0 : *dc_p = dc;
2234 : }
2235 :
2236 136 : return true;
2237 : }
2238 :
2239 : /****************************************************************
2240 : ****************************************************************/
2241 :
2242 100 : static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2243 : struct libnet_JoinCtx *r)
2244 : {
2245 100 : if (!r->in.domain_name) {
2246 0 : libnet_join_set_error_string(mem_ctx, r,
2247 : "No domain name defined");
2248 0 : return WERR_INVALID_PARAMETER;
2249 : }
2250 :
2251 100 : if (strlen(r->in.machine_name) > 15) {
2252 0 : libnet_join_set_error_string(mem_ctx, r,
2253 : "Our netbios name can be at most 15 chars long, "
2254 : "\"%s\" is %u chars long\n",
2255 : r->in.machine_name,
2256 0 : (unsigned int)strlen(r->in.machine_name));
2257 0 : return WERR_INVALID_PARAMETER;
2258 : }
2259 :
2260 100 : r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2261 : r->in.machine_name);
2262 100 : if (r->out.account_name == NULL) {
2263 0 : libnet_join_set_error_string(mem_ctx, r,
2264 : "Unable to construct r->out.account_name");
2265 0 : return WERR_NOT_ENOUGH_MEMORY;
2266 : }
2267 :
2268 100 : if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2269 : &r->in.domain_name,
2270 : &r->in.dc_name)) {
2271 0 : libnet_join_set_error_string(mem_ctx, r,
2272 : "Failed to parse domain name");
2273 0 : return WERR_INVALID_PARAMETER;
2274 : }
2275 :
2276 100 : if (r->in.request_offline_join) {
2277 : /*
2278 : * When in the "request offline join" path we do not have admin
2279 : * credentials available so we can skip the next steps - gd
2280 : */
2281 18 : return WERR_OK;
2282 : }
2283 :
2284 82 : if (r->in.provision_computer_account_only) {
2285 : /*
2286 : * When in the "provision_computer_account_only" path we do not
2287 : * need to have access to secrets.tdb at all - gd
2288 : */
2289 12 : return WERR_OK;
2290 : }
2291 :
2292 70 : if (!secrets_init()) {
2293 0 : libnet_join_set_error_string(mem_ctx, r,
2294 : "Unable to open secrets database");
2295 0 : return WERR_CAN_NOT_COMPLETE;
2296 : }
2297 :
2298 70 : return WERR_OK;
2299 : }
2300 :
2301 : /****************************************************************
2302 : ****************************************************************/
2303 :
2304 75 : static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2305 : {
2306 0 : NTSTATUS status;
2307 :
2308 : /* Try adding dom admins to builtin\admins. Only log failures. */
2309 75 : status = create_builtin_administrators(domain_sid);
2310 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2311 23 : DEBUG(10,("Unable to auto-add domain administrators to "
2312 : "BUILTIN\\Administrators during join because "
2313 : "winbindd must be running.\n"));
2314 52 : } else if (!NT_STATUS_IS_OK(status)) {
2315 44 : DEBUG(5, ("Failed to auto-add domain administrators to "
2316 : "BUILTIN\\Administrators during join: %s\n",
2317 : nt_errstr(status)));
2318 : }
2319 :
2320 : /* Try adding dom users to builtin\users. Only log failures. */
2321 75 : status = create_builtin_users(domain_sid);
2322 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2323 23 : DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2324 : "during join because winbindd must be running.\n"));
2325 52 : } else if (!NT_STATUS_IS_OK(status)) {
2326 44 : DEBUG(5, ("Failed to auto-add domain administrators to "
2327 : "BUILTIN\\Administrators during join: %s\n",
2328 : nt_errstr(status)));
2329 : }
2330 :
2331 : /* Try adding dom guests to builtin\guests. Only log failures. */
2332 75 : status = create_builtin_guests(domain_sid);
2333 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2334 23 : DEBUG(10,("Unable to auto-add domain guests to "
2335 : "BUILTIN\\Guests during join because "
2336 : "winbindd must be running.\n"));
2337 52 : } else if (!NT_STATUS_IS_OK(status)) {
2338 44 : DEBUG(5, ("Failed to auto-add domain guests to "
2339 : "BUILTIN\\Guests during join: %s\n",
2340 : nt_errstr(status)));
2341 : }
2342 75 : }
2343 :
2344 : /****************************************************************
2345 : ****************************************************************/
2346 :
2347 87 : static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2348 : struct libnet_JoinCtx *r)
2349 : {
2350 0 : WERROR werr;
2351 :
2352 87 : if (!W_ERROR_IS_OK(r->out.result)) {
2353 0 : return r->out.result;
2354 : }
2355 :
2356 87 : if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2357 0 : werr = do_JoinConfig(r);
2358 0 : if (!W_ERROR_IS_OK(werr)) {
2359 0 : return werr;
2360 : }
2361 :
2362 0 : return WERR_OK;
2363 : }
2364 :
2365 : #ifdef HAVE_ADS
2366 83 : if (r->out.domain_is_ad &&
2367 78 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2368 0 : ADS_STATUS ads_status;
2369 :
2370 78 : ads_status = libnet_join_post_processing_ads_modify(mem_ctx, r);
2371 78 : if (!ADS_ERR_OK(ads_status)) {
2372 0 : return WERR_GEN_FAILURE;
2373 : }
2374 : }
2375 : #endif /* HAVE_ADS */
2376 :
2377 87 : if (r->in.provision_computer_account_only) {
2378 : /*
2379 : * When we only provision a computer account we are done here - gd.
2380 : */
2381 12 : return WERR_OK;
2382 : }
2383 :
2384 75 : saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2385 75 : if (r->out.dns_domain_name) {
2386 66 : saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2387 : }
2388 :
2389 75 : if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2390 0 : return WERR_NERR_SETUPNOTJOINED;
2391 : }
2392 :
2393 75 : werr = do_JoinConfig(r);
2394 75 : if (!W_ERROR_IS_OK(werr)) {
2395 0 : return werr;
2396 : }
2397 :
2398 : #ifdef HAVE_ADS
2399 71 : if (r->out.domain_is_ad &&
2400 66 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2401 0 : ADS_STATUS ads_status;
2402 :
2403 66 : ads_status = libnet_join_post_processing_ads_sync(mem_ctx, r);
2404 66 : if (!ADS_ERR_OK(ads_status)) {
2405 0 : return WERR_GEN_FAILURE;
2406 : }
2407 : }
2408 : #endif /* HAVE_ADS */
2409 :
2410 75 : libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2411 :
2412 75 : return WERR_OK;
2413 : }
2414 :
2415 : /****************************************************************
2416 : ****************************************************************/
2417 :
2418 104 : static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2419 : {
2420 104 : TALLOC_FREE(r->in.ads);
2421 :
2422 104 : return 0;
2423 : }
2424 :
2425 : /****************************************************************
2426 : ****************************************************************/
2427 :
2428 36 : static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2429 : {
2430 36 : TALLOC_FREE(r->in.ads);
2431 :
2432 36 : return 0;
2433 : }
2434 :
2435 : /****************************************************************
2436 : ****************************************************************/
2437 :
2438 104 : WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2439 : struct libnet_JoinCtx **r)
2440 : {
2441 0 : struct libnet_JoinCtx *ctx;
2442 :
2443 104 : ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2444 104 : if (!ctx) {
2445 0 : return WERR_NOT_ENOUGH_MEMORY;
2446 : }
2447 :
2448 104 : talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2449 :
2450 104 : ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2451 104 : W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2452 :
2453 104 : ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2454 :
2455 104 : ctx->in.desired_encryption_types = 0;
2456 104 : ctx->in.desired_encryption_types |= ENC_RC4_HMAC_MD5;
2457 104 : ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2458 104 : ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2459 :
2460 104 : *r = ctx;
2461 :
2462 104 : return WERR_OK;
2463 : }
2464 :
2465 : /****************************************************************
2466 : ****************************************************************/
2467 :
2468 36 : WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2469 : struct libnet_UnjoinCtx **r)
2470 : {
2471 0 : struct libnet_UnjoinCtx *ctx;
2472 :
2473 36 : ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2474 36 : if (!ctx) {
2475 0 : return WERR_NOT_ENOUGH_MEMORY;
2476 : }
2477 :
2478 36 : talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2479 :
2480 36 : ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2481 36 : W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2482 :
2483 36 : *r = ctx;
2484 :
2485 36 : return WERR_OK;
2486 : }
2487 :
2488 : /****************************************************************
2489 : ****************************************************************/
2490 :
2491 94 : static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2492 : struct libnet_JoinCtx *r)
2493 : {
2494 94 : bool valid_security = false;
2495 94 : bool valid_workgroup = false;
2496 94 : bool valid_realm = false;
2497 94 : bool valid_hostname = false;
2498 94 : bool ignored_realm = false;
2499 :
2500 : /* check if configuration is already set correctly */
2501 :
2502 94 : valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2503 94 : valid_hostname = strequal(lp_netbios_name(), r->in.machine_name);
2504 :
2505 94 : switch (r->out.domain_is_ad) {
2506 16 : case false:
2507 16 : valid_security = (lp_security() == SEC_DOMAIN)
2508 8 : || (lp_server_role() == ROLE_DOMAIN_PDC)
2509 24 : || (lp_server_role() == ROLE_DOMAIN_BDC);
2510 16 : if (valid_workgroup && valid_security) {
2511 : /* nothing to be done */
2512 16 : return WERR_OK;
2513 : }
2514 0 : break;
2515 78 : case true:
2516 78 : valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2517 78 : switch (lp_security()) {
2518 0 : case SEC_DOMAIN:
2519 0 : if (!valid_realm && lp_winbind_rpc_only()) {
2520 0 : valid_realm = true;
2521 0 : ignored_realm = true;
2522 : }
2523 :
2524 : FALL_THROUGH;
2525 : case SEC_ADS:
2526 78 : valid_security = true;
2527 : }
2528 :
2529 78 : if (valid_workgroup && valid_realm && valid_security &&
2530 : valid_hostname) {
2531 78 : if (ignored_realm && !r->in.modify_config)
2532 : {
2533 0 : libnet_join_set_error_string(mem_ctx, r,
2534 : "Warning: ignoring realm when "
2535 : "joining AD domain with "
2536 : "'security=domain' and "
2537 : "'winbind rpc only = yes'. "
2538 : "(realm set to '%s', "
2539 : "should be '%s').", lp_realm(),
2540 : r->out.dns_domain_name);
2541 : }
2542 : /* nothing to be done */
2543 78 : return WERR_OK;
2544 : }
2545 0 : break;
2546 : }
2547 :
2548 : /* check if we are supposed to manipulate configuration */
2549 :
2550 0 : if (!r->in.modify_config) {
2551 :
2552 0 : char *wrong_conf = talloc_strdup(mem_ctx, "");
2553 :
2554 0 : if (!valid_hostname) {
2555 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2556 : "\"netbios name\" set to '%s', should be '%s'",
2557 : lp_netbios_name(), r->in.machine_name);
2558 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2559 : }
2560 :
2561 0 : if (!valid_workgroup) {
2562 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2563 : "\"workgroup\" set to '%s', should be '%s'",
2564 : lp_workgroup(), r->out.netbios_domain_name);
2565 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2566 : }
2567 :
2568 0 : if (!valid_realm) {
2569 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2570 : "\"realm\" set to '%s', should be '%s'",
2571 : lp_realm(), r->out.dns_domain_name);
2572 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2573 : }
2574 :
2575 0 : if (!valid_security) {
2576 0 : const char *sec = NULL;
2577 0 : switch (lp_security()) {
2578 0 : case SEC_USER: sec = "user"; break;
2579 0 : case SEC_DOMAIN: sec = "domain"; break;
2580 0 : case SEC_ADS: sec = "ads"; break;
2581 : }
2582 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2583 : "\"security\" set to '%s', should be %s",
2584 0 : sec, r->out.domain_is_ad ?
2585 : "either 'domain' or 'ads'" : "'domain'");
2586 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2587 : }
2588 :
2589 0 : libnet_join_set_error_string(mem_ctx, r,
2590 : "Invalid configuration (%s) and configuration modification "
2591 : "was not requested", wrong_conf);
2592 0 : return WERR_CAN_NOT_COMPLETE;
2593 : }
2594 :
2595 : /* check if we are able to manipulate configuration */
2596 :
2597 0 : if (!lp_config_backend_is_registry()) {
2598 0 : libnet_join_set_error_string(mem_ctx, r,
2599 : "Configuration manipulation requested but not "
2600 : "supported by backend");
2601 0 : return WERR_NOT_SUPPORTED;
2602 : }
2603 :
2604 0 : return WERR_OK;
2605 : }
2606 :
2607 : /****************************************************************
2608 : ****************************************************************/
2609 :
2610 82 : static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2611 : struct libnet_JoinCtx *r)
2612 : {
2613 0 : NTSTATUS status;
2614 0 : WERROR werr;
2615 82 : struct cli_state *cli = NULL;
2616 : #ifdef HAVE_ADS
2617 0 : ADS_STATUS ads_status;
2618 : #endif /* HAVE_ADS */
2619 82 : const char *pre_connect_realm = NULL;
2620 82 : const char *sitename = NULL;
2621 0 : struct netr_DsRGetDCNameInfo *info;
2622 0 : const char *dc;
2623 82 : uint32_t name_type_flags = 0;
2624 :
2625 : /* Before contacting a DC, we can securely know
2626 : * the realm only if the user specifies it.
2627 : */
2628 82 : if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2629 50 : pre_connect_realm = r->in.domain_name;
2630 : }
2631 :
2632 82 : if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2633 50 : name_type_flags = DS_IS_DNS_NAME;
2634 32 : } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2635 4 : name_type_flags = DS_IS_FLAT_NAME;
2636 : }
2637 :
2638 82 : if (r->in.dc_name) {
2639 22 : status = dsgetonedcname(mem_ctx,
2640 : r->in.msg_ctx,
2641 : r->in.domain_name,
2642 : r->in.dc_name,
2643 : DS_DIRECTORY_SERVICE_REQUIRED |
2644 : DS_WRITABLE_REQUIRED |
2645 : DS_RETURN_DNS_NAME |
2646 : name_type_flags,
2647 : &info);
2648 : } else {
2649 60 : status = dsgetdcname(mem_ctx,
2650 : r->in.msg_ctx,
2651 : r->in.domain_name,
2652 : NULL,
2653 : NULL,
2654 : DS_FORCE_REDISCOVERY |
2655 : DS_DIRECTORY_SERVICE_REQUIRED |
2656 : DS_WRITABLE_REQUIRED |
2657 : DS_RETURN_DNS_NAME |
2658 : name_type_flags,
2659 : &info);
2660 : }
2661 82 : if (!NT_STATUS_IS_OK(status)) {
2662 6 : libnet_join_set_error_string(mem_ctx, r,
2663 : "failed to find DC for domain %s - %s",
2664 : r->in.domain_name,
2665 : get_friendly_nt_error_msg(status));
2666 6 : return WERR_NERR_DCNOTFOUND;
2667 : }
2668 :
2669 76 : dc = strip_hostname(info->dc_unc);
2670 76 : r->in.dc_name = talloc_strdup(mem_ctx, dc);
2671 76 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2672 :
2673 76 : if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2674 76 : info->dc_address[1] != '\\') {
2675 0 : DBG_ERR("ill-formed DC address '%s'\n",
2676 : info->dc_address);
2677 0 : return WERR_NERR_DCNOTFOUND;
2678 : }
2679 :
2680 76 : sitename = info->dc_site_name;
2681 : /* info goes out of scope but the memory stays
2682 : allocated on the talloc context */
2683 :
2684 : /* return the allocated netr_DsRGetDCNameInfo struct */
2685 76 : r->out.dcinfo = info;
2686 :
2687 76 : if (pre_connect_realm != NULL) {
2688 46 : struct sockaddr_storage ss = {0};
2689 46 : const char *numeric_dcip = info->dc_address + 2;
2690 :
2691 46 : if (numeric_dcip[0] == '\0') {
2692 0 : if (!interpret_string_addr(&ss, numeric_dcip,
2693 : AI_NUMERICHOST)) {
2694 0 : DBG_ERR(
2695 : "cannot parse IP address '%s' of DC '%s'\n",
2696 : numeric_dcip, r->in.dc_name);
2697 0 : return WERR_NERR_DCNOTFOUND;
2698 : }
2699 : } else {
2700 46 : if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2701 0 : DBG_WARNING(
2702 : "cannot resolve IP address of DC '%s'\n",
2703 : r->in.dc_name);
2704 0 : return WERR_NERR_DCNOTFOUND;
2705 : }
2706 : }
2707 :
2708 : /* The domain parameter is only used as modifier
2709 : * to krb5.conf file name. _JOIN_ is not a valid
2710 : * NetBIOS name so it cannot clash with another domain
2711 : * -- Uri.
2712 : */
2713 46 : create_local_private_krb5_conf_for_domain(pre_connect_realm,
2714 : "_JOIN_",
2715 : sitename,
2716 : &ss);
2717 : }
2718 :
2719 76 : status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2720 76 : if (!NT_STATUS_IS_OK(status)) {
2721 0 : libnet_join_set_error_string(mem_ctx, r,
2722 : "failed to lookup DC info for domain '%s' over rpc: %s",
2723 : r->in.domain_name, get_friendly_nt_error_msg(status));
2724 0 : return ntstatus_to_werror(status);
2725 : }
2726 :
2727 76 : werr = libnet_join_check_config(mem_ctx, r);
2728 76 : if (!W_ERROR_IS_OK(werr)) {
2729 0 : if (!r->in.provision_computer_account_only) {
2730 0 : goto done;
2731 : }
2732 : /* do not fail when only provisioning */
2733 : }
2734 :
2735 : #ifdef HAVE_ADS
2736 :
2737 69 : if (r->out.domain_is_ad) {
2738 60 : create_local_private_krb5_conf_for_domain(
2739 : r->out.dns_domain_name, r->out.netbios_domain_name,
2740 60 : sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2741 : }
2742 :
2743 69 : if (r->out.domain_is_ad &&
2744 60 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2745 :
2746 60 : const char *initial_account_ou = r->in.account_ou;
2747 :
2748 : /*
2749 : * we want to create the msDS-SupportedEncryptionTypes attribute
2750 : * as early as possible so always try an LDAP create as the user
2751 : * first. We copy r->in.account_ou because it may be changed
2752 : * during the machine pre-creation.
2753 : */
2754 :
2755 60 : ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2756 60 : if (!ADS_ERR_OK(ads_status)) {
2757 0 : libnet_join_set_error_string(mem_ctx, r,
2758 : "failed to connect to AD: %s",
2759 : ads_errstr(ads_status));
2760 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2761 : }
2762 :
2763 60 : ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2764 60 : if (ADS_ERR_OK(ads_status)) {
2765 :
2766 : /*
2767 : * LDAP object creation succeeded.
2768 : */
2769 60 : r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2770 :
2771 60 : return WERR_OK;
2772 : }
2773 :
2774 0 : if (initial_account_ou != NULL) {
2775 0 : libnet_join_set_error_string(mem_ctx, r,
2776 : "failed to precreate account in ou %s: %s",
2777 : r->in.account_ou,
2778 : ads_errstr(ads_status));
2779 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2780 : }
2781 :
2782 0 : DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2783 : r->in.account_ou, ads_errstr(ads_status));
2784 : }
2785 : #endif /* HAVE_ADS */
2786 :
2787 16 : if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2788 9 : (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2789 9 : status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2790 : } else {
2791 7 : status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2792 : }
2793 16 : if (!NT_STATUS_IS_OK(status)) {
2794 7 : libnet_join_set_error_string(mem_ctx, r,
2795 : "failed to join domain '%s' over rpc: %s",
2796 : r->in.domain_name, get_friendly_nt_error_msg(status));
2797 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2798 0 : return WERR_NERR_SETUPALREADYJOINED;
2799 : }
2800 7 : werr = ntstatus_to_werror(status);
2801 7 : goto done;
2802 : }
2803 :
2804 9 : werr = WERR_OK;
2805 :
2806 16 : done:
2807 16 : if (cli) {
2808 16 : cli_shutdown(cli);
2809 : }
2810 :
2811 16 : return werr;
2812 : }
2813 :
2814 : /****************************************************************
2815 : ****************************************************************/
2816 :
2817 18 : static WERROR libnet_DomainOfflineJoin(TALLOC_CTX *mem_ctx,
2818 : struct libnet_JoinCtx *r)
2819 : {
2820 0 : NTSTATUS status;
2821 0 : WERROR werr;
2822 0 : struct ODJ_WIN7BLOB win7blob;
2823 0 : struct OP_JOINPROV3_PART joinprov3;
2824 0 : const char *dc_name;
2825 :
2826 18 : if (!r->in.request_offline_join) {
2827 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2828 : }
2829 :
2830 18 : if (r->in.odj_provision_data == NULL) {
2831 0 : return WERR_INVALID_PARAMETER;
2832 : }
2833 :
2834 18 : werr = libnet_odj_find_win7blob(r->in.odj_provision_data, &win7blob);
2835 18 : if (!W_ERROR_IS_OK(werr)) {
2836 0 : return werr;
2837 : }
2838 :
2839 18 : r->out.netbios_domain_name = talloc_strdup(mem_ctx,
2840 : win7blob.DnsDomainInfo.Name.string);
2841 18 : W_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
2842 :
2843 18 : r->out.dns_domain_name = talloc_strdup(mem_ctx,
2844 : win7blob.DnsDomainInfo.DnsDomainName.string);
2845 18 : W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2846 :
2847 18 : r->out.forest_name = talloc_strdup(mem_ctx,
2848 : win7blob.DnsDomainInfo.DnsForestName.string);
2849 18 : W_ERROR_HAVE_NO_MEMORY(r->out.forest_name);
2850 :
2851 18 : r->out.domain_guid = win7blob.DnsDomainInfo.DomainGuid;
2852 36 : r->out.domain_sid = dom_sid_dup(mem_ctx,
2853 18 : win7blob.DnsDomainInfo.Sid);
2854 18 : W_ERROR_HAVE_NO_MEMORY(r->out.domain_sid);
2855 :
2856 18 : werr = libnet_odj_find_joinprov3(r->in.odj_provision_data, &joinprov3);
2857 18 : if (!W_ERROR_IS_OK(werr)) {
2858 0 : return werr;
2859 : }
2860 :
2861 18 : r->out.account_rid = joinprov3.Rid;
2862 :
2863 18 : dc_name = strip_hostname(win7blob.DcInfo.dc_address);
2864 18 : if (dc_name == NULL) {
2865 0 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
2866 : }
2867 18 : r->in.dc_name = talloc_strdup(mem_ctx, dc_name);
2868 18 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2869 :
2870 18 : r->out.domain_is_ad = true;
2871 :
2872 : /* we cannot use talloc_steal but have to deep copy the struct here */
2873 18 : status = copy_netr_DsRGetDCNameInfo(mem_ctx, &win7blob.DcInfo,
2874 : &r->out.dcinfo);
2875 18 : if (!NT_STATUS_IS_OK(status)) {
2876 0 : return ntstatus_to_werror(status);
2877 : }
2878 :
2879 18 : werr = libnet_join_check_config(mem_ctx, r);
2880 18 : if (!W_ERROR_IS_OK(werr)) {
2881 0 : return werr;
2882 : }
2883 :
2884 18 : return WERR_OK;
2885 : #if 0
2886 : /* the following fields are currently not filled in */
2887 :
2888 : const char * dn;
2889 : uint32_t set_encryption_types;
2890 : const char * krb5_salt;
2891 : #endif
2892 : }
2893 :
2894 : /****************************************************************
2895 : ****************************************************************/
2896 :
2897 0 : static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2898 : struct libnet_JoinCtx *r)
2899 : {
2900 0 : WERROR werr;
2901 0 : struct libnet_UnjoinCtx *u = NULL;
2902 :
2903 0 : werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2904 0 : if (!W_ERROR_IS_OK(werr)) {
2905 0 : return werr;
2906 : }
2907 :
2908 0 : u->in.debug = r->in.debug;
2909 0 : u->in.dc_name = r->in.dc_name;
2910 0 : u->in.domain_name = r->in.domain_name;
2911 0 : u->in.admin_credentials = r->in.admin_credentials;
2912 0 : u->in.modify_config = r->in.modify_config;
2913 0 : u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2914 : WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2915 :
2916 0 : werr = libnet_Unjoin(mem_ctx, u);
2917 0 : TALLOC_FREE(u);
2918 :
2919 0 : return werr;
2920 : }
2921 :
2922 : /****************************************************************
2923 : ****************************************************************/
2924 :
2925 100 : WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2926 : struct libnet_JoinCtx *r)
2927 : {
2928 0 : WERROR werr;
2929 :
2930 100 : if (r->in.debug) {
2931 92 : LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2932 : }
2933 :
2934 100 : ZERO_STRUCT(r->out);
2935 :
2936 100 : werr = libnet_join_pre_processing(mem_ctx, r);
2937 100 : if (!W_ERROR_IS_OK(werr)) {
2938 0 : goto done;
2939 : }
2940 :
2941 100 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2942 100 : if (r->in.request_offline_join) {
2943 18 : werr = libnet_DomainOfflineJoin(mem_ctx, r);
2944 : } else {
2945 82 : werr = libnet_DomainJoin(mem_ctx, r);
2946 : }
2947 100 : if (!W_ERROR_IS_OK(werr)) {
2948 13 : goto done;
2949 : }
2950 : }
2951 :
2952 87 : werr = libnet_join_post_processing(mem_ctx, r);
2953 87 : if (!W_ERROR_IS_OK(werr)) {
2954 0 : goto done;
2955 : }
2956 :
2957 87 : if (r->in.provision_computer_account_only) {
2958 : /*
2959 : * When we only provision a computer account we are done here - gd.
2960 : */
2961 12 : goto done;
2962 : }
2963 :
2964 75 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2965 75 : if (r->in.request_offline_join) {
2966 : /*
2967 : * When we are serving an offline domain join request we
2968 : * have no network so we are done here - gd.
2969 : */
2970 18 : goto done;
2971 : }
2972 :
2973 57 : werr = libnet_join_post_verify(mem_ctx, r);
2974 57 : if (!W_ERROR_IS_OK(werr)) {
2975 0 : libnet_join_rollback(mem_ctx, r);
2976 : }
2977 : }
2978 :
2979 57 : done:
2980 100 : r->out.result = werr;
2981 :
2982 100 : if (r->in.debug) {
2983 92 : LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2984 : }
2985 100 : return werr;
2986 : }
2987 :
2988 : /****************************************************************
2989 : ****************************************************************/
2990 :
2991 36 : static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2992 : struct libnet_UnjoinCtx *r)
2993 : {
2994 0 : NTSTATUS status;
2995 :
2996 36 : if (!r->in.domain_sid) {
2997 0 : struct dom_sid sid;
2998 36 : if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2999 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3000 : "Unable to fetch domain sid: are we joined?");
3001 0 : return WERR_NERR_SETUPNOTJOINED;
3002 : }
3003 36 : r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
3004 36 : W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
3005 : }
3006 :
3007 36 : if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
3008 0 : !r->in.delete_machine_account) {
3009 0 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3010 0 : return WERR_OK;
3011 : }
3012 :
3013 36 : if (!r->in.dc_name) {
3014 0 : struct netr_DsRGetDCNameInfo *info;
3015 0 : const char *dc;
3016 30 : status = dsgetdcname(mem_ctx,
3017 : r->in.msg_ctx,
3018 : r->in.domain_name,
3019 : NULL,
3020 : NULL,
3021 : DS_DIRECTORY_SERVICE_REQUIRED |
3022 : DS_WRITABLE_REQUIRED |
3023 : DS_RETURN_DNS_NAME,
3024 : &info);
3025 30 : if (!NT_STATUS_IS_OK(status)) {
3026 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3027 : "failed to find DC for domain %s - %s",
3028 : r->in.domain_name,
3029 : get_friendly_nt_error_msg(status));
3030 0 : return WERR_NERR_DCNOTFOUND;
3031 : }
3032 :
3033 30 : dc = strip_hostname(info->dc_unc);
3034 30 : r->in.dc_name = talloc_strdup(mem_ctx, dc);
3035 30 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
3036 : }
3037 :
3038 : #ifdef HAVE_ADS
3039 : /* for net ads leave, try to delete the account. If it works,
3040 : no sense in disabling. If it fails, we can still try to
3041 : disable it. jmcd */
3042 :
3043 36 : if (r->in.delete_machine_account) {
3044 0 : ADS_STATUS ads_status;
3045 34 : ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
3046 34 : if (ADS_ERR_OK(ads_status)) {
3047 : /* dirty hack */
3048 32 : r->out.dns_domain_name =
3049 32 : talloc_strdup(mem_ctx,
3050 32 : r->in.ads->server.realm);
3051 0 : ads_status =
3052 32 : libnet_unjoin_remove_machine_acct(mem_ctx, r);
3053 : }
3054 34 : if (!ADS_ERR_OK(ads_status)) {
3055 2 : libnet_unjoin_set_error_string(mem_ctx, r,
3056 : "failed to remove machine account from AD: %s",
3057 : ads_errstr(ads_status));
3058 : } else {
3059 32 : r->out.deleted_machine_account = true;
3060 32 : W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
3061 32 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3062 32 : return WERR_OK;
3063 : }
3064 : }
3065 : #endif /* HAVE_ADS */
3066 :
3067 : /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
3068 : "disable". */
3069 4 : if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
3070 4 : status = libnet_join_unjoindomain_rpc(mem_ctx, r);
3071 4 : if (!NT_STATUS_IS_OK(status)) {
3072 2 : libnet_unjoin_set_error_string(mem_ctx, r,
3073 : "failed to disable machine account via rpc: %s",
3074 : get_friendly_nt_error_msg(status));
3075 2 : if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
3076 0 : return WERR_NERR_SETUPNOTJOINED;
3077 : }
3078 2 : return ntstatus_to_werror(status);
3079 : }
3080 :
3081 2 : r->out.dns_domain_name = talloc_strdup(mem_ctx,
3082 : r->in.domain_name);
3083 2 : r->out.disabled_machine_account = true;
3084 : }
3085 :
3086 : /* If disable succeeded or was not requested at all, we
3087 : should be getting rid of our end of things */
3088 :
3089 2 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3090 :
3091 2 : return WERR_OK;
3092 : }
3093 :
3094 : /****************************************************************
3095 : ****************************************************************/
3096 :
3097 36 : static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
3098 : struct libnet_UnjoinCtx *r)
3099 : {
3100 36 : if (!r->in.domain_name) {
3101 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3102 : "No domain name defined");
3103 0 : return WERR_INVALID_PARAMETER;
3104 : }
3105 :
3106 36 : if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
3107 : &r->in.domain_name,
3108 : &r->in.dc_name)) {
3109 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3110 : "Failed to parse domain name");
3111 0 : return WERR_INVALID_PARAMETER;
3112 : }
3113 :
3114 36 : if (IS_DC) {
3115 0 : return WERR_NERR_SETUPDOMAINCONTROLLER;
3116 : }
3117 :
3118 36 : if (!secrets_init()) {
3119 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3120 : "Unable to open secrets database");
3121 0 : return WERR_CAN_NOT_COMPLETE;
3122 : }
3123 :
3124 36 : return WERR_OK;
3125 : }
3126 :
3127 : /****************************************************************
3128 : ****************************************************************/
3129 :
3130 34 : static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
3131 : struct libnet_UnjoinCtx *r)
3132 : {
3133 34 : saf_delete(r->out.netbios_domain_name);
3134 34 : saf_delete(r->out.dns_domain_name);
3135 :
3136 34 : return libnet_unjoin_config(r);
3137 : }
3138 :
3139 : /****************************************************************
3140 : ****************************************************************/
3141 :
3142 36 : WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
3143 : struct libnet_UnjoinCtx *r)
3144 : {
3145 0 : WERROR werr;
3146 :
3147 36 : if (r->in.debug) {
3148 34 : LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
3149 : }
3150 :
3151 36 : werr = libnet_unjoin_pre_processing(mem_ctx, r);
3152 36 : if (!W_ERROR_IS_OK(werr)) {
3153 0 : goto done;
3154 : }
3155 :
3156 36 : if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3157 36 : werr = libnet_DomainUnjoin(mem_ctx, r);
3158 36 : if (!W_ERROR_IS_OK(werr)) {
3159 2 : libnet_unjoin_config(r);
3160 2 : goto done;
3161 : }
3162 : }
3163 :
3164 34 : werr = libnet_unjoin_post_processing(mem_ctx, r);
3165 34 : if (!W_ERROR_IS_OK(werr)) {
3166 0 : goto done;
3167 : }
3168 :
3169 34 : done:
3170 36 : r->out.result = werr;
3171 :
3172 36 : if (r->in.debug) {
3173 34 : LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
3174 : }
3175 :
3176 36 : return werr;
3177 : }
|