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