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 13 : static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
89 : struct libnet_JoinCtx *r,
90 : const char *format, ...)
91 : {
92 0 : va_list args;
93 :
94 13 : if (r->out.error_string) {
95 0 : return;
96 : }
97 :
98 13 : va_start(args, format);
99 13 : r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
100 13 : 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 6 : static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
112 : struct libnet_UnjoinCtx *r,
113 : const char *format, ...)
114 : {
115 0 : va_list args;
116 :
117 6 : if (r->out.error_string) {
118 4 : return;
119 : }
120 :
121 2 : va_start(args, format);
122 2 : r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
123 2 : va_end(args);
124 : }
125 :
126 : #ifdef HAVE_ADS
127 :
128 : /****************************************************************
129 : ****************************************************************/
130 :
131 148 : 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 148 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
141 0 : ADS_STATUS status;
142 148 : ADS_STRUCT *my_ads = NULL;
143 0 : char *cp;
144 0 : enum credentials_use_kerberos krb5_state;
145 :
146 148 : my_ads = ads_init(tmp_ctx,
147 : dns_domain_name,
148 : netbios_domain_name,
149 : dc_name,
150 : ADS_SASL_SEAL);
151 148 : 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 148 : krb5_state = lp_client_use_kerberos();
158 148 : 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 148 : case CRED_USE_KERBEROS_DESIRED:
164 148 : my_ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
165 148 : my_ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
166 148 : 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 148 : if (user_name) {
174 148 : ADS_TALLOC_CONST_FREE(my_ads->auth.user_name);
175 148 : my_ads->auth.user_name = talloc_strdup(my_ads, user_name);
176 148 : if (my_ads->auth.user_name == NULL) {
177 0 : status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
178 0 : goto out;
179 : }
180 148 : if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
181 60 : *cp++ = '\0';
182 60 : ADS_TALLOC_CONST_FREE(my_ads->auth.realm);
183 60 : my_ads->auth.realm = talloc_asprintf_strupper_m(my_ads, "%s", cp);
184 60 : if (my_ads->auth.realm == NULL) {
185 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
186 0 : goto out;
187 : }
188 : }
189 : }
190 :
191 148 : if (password) {
192 148 : ADS_TALLOC_CONST_FREE(my_ads->auth.password);
193 148 : my_ads->auth.password = talloc_strdup(my_ads, password);
194 148 : if (my_ads->auth.password == NULL) {
195 0 : status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
196 0 : goto out;
197 : }
198 : }
199 :
200 148 : if (ccname != NULL) {
201 96 : ADS_TALLOC_CONST_FREE(my_ads->auth.ccache_name);
202 96 : my_ads->auth.ccache_name = talloc_strdup(my_ads, ccname);
203 96 : if (my_ads->auth.ccache_name == NULL) {
204 0 : status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
205 0 : goto out;
206 : }
207 96 : setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
208 : }
209 :
210 148 : status = ads_connect_user_creds(my_ads);
211 148 : if (!ADS_ERR_OK(status)) {
212 2 : goto out;
213 : }
214 :
215 146 : *ads = talloc_move(mem_ctx, &my_ads);
216 :
217 146 : status = ADS_SUCCESS;
218 148 : out:
219 148 : TALLOC_FREE(tmp_ctx);
220 148 : return status;
221 : }
222 :
223 : /****************************************************************
224 : ****************************************************************/
225 :
226 114 : static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
227 : struct libnet_JoinCtx *r,
228 : bool use_machine_creds)
229 : {
230 0 : ADS_STATUS status;
231 0 : const char *username;
232 0 : const char *password;
233 114 : const char *ccname = NULL;
234 :
235 114 : if (use_machine_creds) {
236 54 : if (r->in.machine_name == NULL ||
237 54 : r->in.machine_password == NULL) {
238 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
239 : }
240 54 : username = talloc_asprintf(mem_ctx, "%s$",
241 : r->in.machine_name);
242 54 : if (username == NULL) {
243 0 : return ADS_ERROR(LDAP_NO_MEMORY);
244 : }
245 54 : password = r->in.machine_password;
246 54 : ccname = "MEMORY:libnet_join_machine_creds";
247 : } else {
248 60 : char *p = NULL;
249 :
250 60 : username = r->in.admin_account;
251 :
252 60 : p = strchr(r->in.admin_account, '@');
253 60 : if (p == NULL) {
254 60 : username = talloc_asprintf(mem_ctx, "%s@%s",
255 : r->in.admin_account,
256 : r->in.admin_domain);
257 : }
258 60 : if (username == NULL) {
259 0 : return ADS_ERROR(LDAP_NO_MEMORY);
260 : }
261 60 : 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 60 : if (!r->in.use_kerberos) {
269 42 : ccname = "MEMORY:libnet_join_user_creds";
270 : }
271 : }
272 :
273 114 : 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 114 : &r->in.ads);
281 114 : 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 114 : 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 114 : 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 114 : r->out.domain_is_ad = true;
301 :
302 114 : return ADS_SUCCESS;
303 : }
304 :
305 : /****************************************************************
306 : ****************************************************************/
307 :
308 60 : static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
309 : struct libnet_JoinCtx *r)
310 : {
311 60 : return libnet_join_connect_ads(mem_ctx, r, false);
312 : }
313 :
314 : /****************************************************************
315 : ****************************************************************/
316 :
317 54 : static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
318 : struct libnet_JoinCtx *r)
319 : {
320 54 : return libnet_join_connect_ads(mem_ctx, r, true);
321 : }
322 :
323 : /****************************************************************
324 : ****************************************************************/
325 :
326 34 : static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
327 : struct libnet_UnjoinCtx *r)
328 : {
329 0 : ADS_STATUS status;
330 :
331 34 : 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 34 : &r->in.ads);
339 34 : if (!ADS_ERR_OK(status)) {
340 2 : libnet_unjoin_set_error_string(mem_ctx, r,
341 : "failed to connect to AD: %s",
342 : ads_errstr(status));
343 : }
344 :
345 34 : return status;
346 : }
347 :
348 : /****************************************************************
349 : join a domain using ADS (LDAP mods)
350 : ****************************************************************/
351 :
352 60 : static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
353 : struct libnet_JoinCtx *r)
354 : {
355 0 : ADS_STATUS status;
356 60 : LDAPMessage *res = NULL;
357 60 : const char *attrs[] = { "dn", NULL };
358 60 : bool moved = false;
359 :
360 60 : status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
361 60 : if (!ADS_ERR_OK(status)) {
362 0 : return status;
363 : }
364 :
365 60 : status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
366 60 : if (!ADS_ERR_OK(status)) {
367 0 : return status;
368 : }
369 :
370 60 : 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 60 : 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 60 : if (r->in.machine_password == NULL) {
381 52 : r->in.machine_password =
382 52 : trust_pw_new_value(mem_ctx,
383 : r->in.secure_channel_type,
384 : SEC_ADS);
385 52 : if (r->in.machine_password == NULL) {
386 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
387 : }
388 : }
389 :
390 60 : 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 60 : if (ADS_ERR_OK(status)) {
398 60 : DBG_WARNING("Machine account successfully created\n");
399 60 : 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 32 : static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
430 : struct libnet_UnjoinCtx *r)
431 : {
432 0 : ADS_STATUS status;
433 :
434 32 : 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 32 : status = ads_leave_realm(r->in.ads, r->in.machine_name);
445 32 : 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 32 : return ADS_SUCCESS;
453 : }
454 :
455 : /****************************************************************
456 : ****************************************************************/
457 :
458 176 : static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
459 : struct libnet_JoinCtx *r)
460 : {
461 0 : ADS_STATUS status;
462 176 : LDAPMessage *res = NULL;
463 176 : char *dn = NULL;
464 0 : struct dom_sid sid;
465 :
466 176 : if (!r->in.machine_name) {
467 0 : return ADS_ERROR(LDAP_NO_MEMORY);
468 : }
469 :
470 176 : status = ads_find_machine_acct(r->in.ads,
471 : &res,
472 : r->in.machine_name);
473 176 : if (!ADS_ERR_OK(status)) {
474 0 : return status;
475 : }
476 :
477 176 : 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 176 : dn = ads_get_dn(r->in.ads, mem_ctx, res);
483 176 : if (!dn) {
484 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
485 0 : goto done;
486 : }
487 :
488 176 : r->out.dn = talloc_strdup(mem_ctx, dn);
489 176 : if (!r->out.dn) {
490 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
491 0 : goto done;
492 : }
493 :
494 176 : if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
495 : &r->out.set_encryption_types)) {
496 168 : r->out.set_encryption_types = 0;
497 : }
498 :
499 176 : 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 176 : dom_sid_split_rid(mem_ctx, &sid, NULL, &r->out.account_rid);
505 176 : done:
506 176 : ads_msgfree(r->in.ads, res);
507 176 : TALLOC_FREE(dn);
508 :
509 176 : return status;
510 : }
511 :
512 60 : 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 0 : ADS_STATUS status;
518 :
519 60 : if (r->in.machine_name == NULL) {
520 0 : return ADS_ERROR_SYSTEM(EINVAL);
521 : }
522 :
523 60 : status = ads_get_service_principal_names(mem_ctx,
524 60 : r->in.ads,
525 : r->in.machine_name,
526 : spn_array,
527 : num_spns);
528 :
529 60 : return status;
530 : }
531 :
532 140 : static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const char *spn,
533 : const char ***array, size_t *num)
534 : {
535 140 : bool ok = ads_element_in_array(*array, *num, spn);
536 140 : if (!ok) {
537 24 : ok = add_string_to_array(mem_ctx, spn, array, num);
538 24 : if (!ok) {
539 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
540 : }
541 : }
542 140 : return ADS_SUCCESS;
543 : }
544 :
545 : /****************************************************************
546 : Set a machines dNSHostName and servicePrincipalName attributes
547 : ****************************************************************/
548 :
549 60 : static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
550 : struct libnet_JoinCtx *r)
551 : {
552 60 : TALLOC_CTX *frame = talloc_stackframe();
553 0 : ADS_STATUS status;
554 0 : ADS_MODLIST mods;
555 0 : fstring my_fqdn;
556 0 : fstring my_alias;
557 60 : const char **spn_array = NULL;
558 60 : size_t num_spns = 0;
559 60 : char *spn = NULL;
560 60 : const char **netbios_aliases = NULL;
561 60 : const char **addl_hostnames = NULL;
562 :
563 : /* Find our DN */
564 :
565 60 : status = libnet_join_find_machine_acct(mem_ctx, r);
566 60 : if (!ADS_ERR_OK(status)) {
567 0 : goto done;
568 : }
569 :
570 60 : status = libnet_join_get_machine_spns(frame,
571 : r,
572 : discard_const_p(char **, &spn_array),
573 : &num_spns);
574 60 : 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 60 : spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name);
581 60 : if (spn == NULL) {
582 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
583 0 : goto done;
584 : }
585 60 : if (!strupper_m(spn)) {
586 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
587 0 : goto done;
588 : }
589 :
590 60 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
591 60 : if (!ADS_ERR_OK(status)) {
592 0 : goto done;
593 : }
594 :
595 60 : if (r->in.dnshostname != NULL) {
596 10 : fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
597 : } else {
598 50 : fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
599 : lp_dnsdomain());
600 : }
601 :
602 60 : if (!strlower_m(my_fqdn)) {
603 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
604 0 : goto done;
605 : }
606 :
607 60 : spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
608 60 : if (spn == NULL) {
609 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
610 0 : goto done;
611 : }
612 :
613 60 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
614 60 : if (!ADS_ERR_OK(status)) {
615 0 : goto done;
616 : }
617 :
618 60 : for (netbios_aliases = lp_netbios_aliases();
619 68 : netbios_aliases != NULL && *netbios_aliases != NULL;
620 8 : netbios_aliases++) {
621 : /*
622 : * Add HOST/NETBIOSNAME
623 : */
624 8 : spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases);
625 8 : if (spn == NULL) {
626 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
627 0 : goto done;
628 : }
629 8 : if (!strupper_m(spn)) {
630 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
631 0 : goto done;
632 : }
633 :
634 8 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
635 8 : if (!ADS_ERR_OK(status)) {
636 0 : goto done;
637 : }
638 :
639 : /*
640 : * Add HOST/netbiosname.domainname
641 : */
642 8 : fstr_sprintf(my_alias, "%s.%s",
643 : *netbios_aliases,
644 : lp_dnsdomain());
645 :
646 8 : spn = talloc_asprintf(frame, "HOST/%s", my_alias);
647 8 : if (spn == NULL) {
648 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
649 0 : goto done;
650 : }
651 :
652 8 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
653 8 : if (!ADS_ERR_OK(status)) {
654 0 : goto done;
655 : }
656 : }
657 :
658 60 : for (addl_hostnames = lp_additional_dns_hostnames();
659 64 : addl_hostnames != NULL && *addl_hostnames != NULL;
660 4 : addl_hostnames++) {
661 :
662 4 : spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames);
663 4 : if (spn == NULL) {
664 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
665 0 : goto done;
666 : }
667 :
668 4 : status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
669 4 : if (!ADS_ERR_OK(status)) {
670 0 : goto done;
671 : }
672 : }
673 :
674 : /* make sure to NULL terminate the array */
675 60 : spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1);
676 60 : if (spn_array == NULL) {
677 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
678 0 : goto done;
679 : }
680 60 : spn_array[num_spns] = NULL;
681 :
682 60 : mods = ads_init_mods(mem_ctx);
683 60 : if (!mods) {
684 0 : status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
685 0 : goto done;
686 : }
687 :
688 : /* fields of primary importance */
689 :
690 60 : status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
691 60 : if (!ADS_ERR_OK(status)) {
692 0 : goto done;
693 : }
694 :
695 60 : status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
696 : spn_array);
697 60 : if (!ADS_ERR_OK(status)) {
698 0 : goto done;
699 : }
700 :
701 60 : addl_hostnames = lp_additional_dns_hostnames();
702 60 : if (addl_hostnames != NULL && *addl_hostnames != NULL) {
703 2 : status = ads_mod_strlist(mem_ctx, &mods,
704 : "msDS-AdditionalDnsHostName",
705 : addl_hostnames);
706 2 : if (!ADS_ERR_OK(status)) {
707 0 : goto done;
708 : }
709 : }
710 :
711 60 : status = ads_gen_mod(r->in.ads, r->out.dn, mods);
712 :
713 60 : done:
714 60 : TALLOC_FREE(frame);
715 60 : return status;
716 : }
717 :
718 : /****************************************************************
719 : ****************************************************************/
720 :
721 60 : static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
722 : struct libnet_JoinCtx *r)
723 : {
724 0 : ADS_STATUS status;
725 0 : ADS_MODLIST mods;
726 :
727 60 : if (!r->in.create_upn) {
728 58 : return ADS_SUCCESS;
729 : }
730 :
731 : /* Find our DN */
732 :
733 2 : status = libnet_join_find_machine_acct(mem_ctx, r);
734 2 : if (!ADS_ERR_OK(status)) {
735 0 : return status;
736 : }
737 :
738 2 : 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 2 : mods = ads_init_mods(mem_ctx);
766 2 : if (!mods) {
767 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
768 : }
769 :
770 : /* fields of primary importance */
771 :
772 2 : status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
773 2 : if (!ADS_ERR_OK(status)) {
774 0 : return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
775 : }
776 :
777 2 : return ads_gen_mod(r->in.ads, r->out.dn, mods);
778 : }
779 :
780 :
781 : /****************************************************************
782 : ****************************************************************/
783 :
784 60 : static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
785 : struct libnet_JoinCtx *r)
786 : {
787 0 : ADS_STATUS status;
788 0 : ADS_MODLIST mods;
789 60 : char *os_sp = NULL;
790 :
791 60 : if (!r->in.os_name || !r->in.os_version ) {
792 60 : 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 54 : static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
852 : struct libnet_JoinCtx *r)
853 : {
854 0 : ADS_STATUS status;
855 0 : ADS_MODLIST mods;
856 0 : const char *etype_list_str;
857 :
858 54 : etype_list_str = talloc_asprintf(mem_ctx, "%d",
859 : r->in.desired_encryption_types);
860 54 : if (!etype_list_str) {
861 0 : return ADS_ERROR(LDAP_NO_MEMORY);
862 : }
863 :
864 : /* Find our DN */
865 :
866 54 : status = libnet_join_find_machine_acct(mem_ctx, r);
867 54 : if (!ADS_ERR_OK(status)) {
868 0 : return status;
869 : }
870 :
871 54 : 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 54 : mods = ads_init_mods(mem_ctx);
878 54 : if (!mods) {
879 0 : return ADS_ERROR(LDAP_NO_MEMORY);
880 : }
881 :
882 54 : status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
883 : etype_list_str);
884 54 : if (!ADS_ERR_OK(status)) {
885 0 : return status;
886 : }
887 :
888 54 : status = ads_gen_mod(r->in.ads, r->out.dn, mods);
889 54 : if (!ADS_ERR_OK(status)) {
890 0 : return status;
891 : }
892 :
893 54 : r->out.set_encryption_types = r->in.desired_encryption_types;
894 :
895 54 : return ADS_SUCCESS;
896 : }
897 :
898 : /****************************************************************
899 : ****************************************************************/
900 :
901 66 : static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
902 : struct libnet_JoinCtx *r)
903 : {
904 66 : if (!USE_SYSTEM_KEYTAB) {
905 66 : 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 60 : static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
919 : struct libnet_JoinCtx *r)
920 : {
921 0 : uint32_t domain_func;
922 0 : ADS_STATUS status;
923 60 : const char *salt = NULL;
924 60 : char *std_salt = NULL;
925 :
926 60 : status = ads_domain_func_level(r->in.ads, &domain_func);
927 60 : 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 60 : std_salt = kerberos_standard_des_salt();
937 60 : 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 60 : salt = talloc_strdup(mem_ctx, std_salt);
944 60 : if (!salt) {
945 0 : return false;
946 : }
947 :
948 60 : SAFE_FREE(std_salt);
949 :
950 : /* if it's a Windows functional domain, we have to look for the UPN */
951 :
952 60 : if (domain_func == DS_DOMAIN_FUNCTION_2000) {
953 0 : 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 60 : r->out.krb5_salt = salt;
966 60 : return true;
967 : }
968 :
969 : /****************************************************************
970 : ****************************************************************/
971 :
972 78 : static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
973 : struct libnet_JoinCtx *r)
974 : {
975 0 : ADS_STATUS status;
976 78 : bool need_etype_update = false;
977 :
978 78 : 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 18 : return ADS_SUCCESS;
984 : }
985 :
986 60 : 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 60 : status = libnet_join_set_machine_spn(mem_ctx, r);
994 60 : 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 60 : status = libnet_join_set_os_attributes(mem_ctx, r);
1004 60 : 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 60 : status = libnet_join_set_machine_upn(mem_ctx, r);
1012 60 : 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 60 : status = libnet_join_find_machine_acct(mem_ctx, r);
1020 60 : if (!ADS_ERR_OK(status)) {
1021 0 : return status;
1022 : }
1023 :
1024 60 : if (r->in.desired_encryption_types != r->out.set_encryption_types) {
1025 56 : uint32_t func_level = 0;
1026 :
1027 56 : status = ads_domain_func_level(r->in.ads, &func_level);
1028 56 : 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 56 : if (func_level >= DS_DOMAIN_FUNCTION_2008) {
1036 54 : need_etype_update = true;
1037 : }
1038 : }
1039 :
1040 60 : if (need_etype_update) {
1041 : /*
1042 : * We need to reconnect as machine account in order
1043 : * to update msDS-SupportedEncryptionTypes reliable
1044 : */
1045 :
1046 54 : if (r->in.ads->auth.ccache_name != NULL) {
1047 38 : ads_kdestroy(r->in.ads->auth.ccache_name);
1048 38 : ADS_TALLOC_CONST_FREE(r->in.ads->auth.ccache_name);
1049 : }
1050 :
1051 54 : TALLOC_FREE(r->in.ads);
1052 :
1053 54 : status = libnet_join_connect_ads_machine(mem_ctx, r);
1054 54 : 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 54 : status = libnet_join_set_etypes(mem_ctx, r);
1062 54 : 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 60 : if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1071 0 : return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1072 : }
1073 :
1074 60 : return ADS_SUCCESS;
1075 : }
1076 :
1077 66 : static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
1078 : struct libnet_JoinCtx *r)
1079 : {
1080 66 : 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 66 : return ADS_SUCCESS;
1087 : }
1088 : #endif /* HAVE_ADS */
1089 :
1090 : /****************************************************************
1091 : Store the machine password and domain SID
1092 : ****************************************************************/
1093 :
1094 75 : static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1095 : struct libnet_JoinCtx *r)
1096 : {
1097 0 : NTSTATUS status;
1098 :
1099 75 : status = secrets_store_JoinCtx(r);
1100 75 : 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 75 : return true;
1107 : }
1108 :
1109 : /****************************************************************
1110 : Connect dc's IPC$ share
1111 : ****************************************************************/
1112 :
1113 80 : 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 80 : TALLOC_CTX *frame = talloc_stackframe();
1121 80 : bool fallback_after_kerberos = false;
1122 80 : bool use_ccache = false;
1123 80 : bool pw_nt_hash = false;
1124 80 : struct cli_credentials *creds = NULL;
1125 80 : int flags = CLI_FULL_CONNECTION_IPC;
1126 0 : NTSTATUS status;
1127 :
1128 80 : if (use_kerberos && pass) {
1129 18 : fallback_after_kerberos = true;
1130 : }
1131 :
1132 80 : 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 80 : if (creds == NULL) {
1142 0 : TALLOC_FREE(frame);
1143 0 : return NT_STATUS_NO_MEMORY;
1144 : }
1145 :
1146 80 : status = cli_full_connection_creds(cli,
1147 : NULL,
1148 : dc,
1149 : NULL, 0,
1150 : "IPC$", "IPC",
1151 : creds,
1152 : flags);
1153 80 : if (!NT_STATUS_IS_OK(status)) {
1154 2 : TALLOC_FREE(frame);
1155 2 : return status;
1156 : }
1157 :
1158 78 : TALLOC_FREE(frame);
1159 78 : return NT_STATUS_OK;
1160 : }
1161 :
1162 : /****************************************************************
1163 : Lookup domain dc's info
1164 : ****************************************************************/
1165 :
1166 76 : static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1167 : struct libnet_JoinCtx *r,
1168 : struct cli_state **cli)
1169 : {
1170 76 : struct rpc_pipe_client *pipe_hnd = NULL;
1171 0 : struct policy_handle lsa_pol;
1172 0 : NTSTATUS status, result;
1173 76 : union lsa_PolicyInformation *info = NULL;
1174 0 : struct dcerpc_binding_handle *b;
1175 76 : const char *account = r->in.admin_account;
1176 76 : const char *domain = r->in.admin_domain;
1177 76 : const char *password = r->in.admin_password;
1178 76 : bool use_kerberos = r->in.use_kerberos;
1179 :
1180 76 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1181 9 : account = "";
1182 9 : domain = "";
1183 9 : password = NULL;
1184 9 : use_kerberos = false;
1185 : }
1186 :
1187 76 : status = libnet_join_connect_dc_ipc(r->in.dc_name,
1188 : account,
1189 : domain,
1190 : password,
1191 : use_kerberos,
1192 : cli);
1193 76 : if (!NT_STATUS_IS_OK(status)) {
1194 0 : goto done;
1195 : }
1196 :
1197 76 : status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1198 : &pipe_hnd);
1199 76 : 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 76 : b = pipe_hnd->binding_handle;
1206 :
1207 76 : status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1208 : SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1209 76 : if (!NT_STATUS_IS_OK(status)) {
1210 0 : goto done;
1211 : }
1212 :
1213 76 : status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1214 : &lsa_pol,
1215 : LSA_POLICY_INFO_DNS,
1216 : &info,
1217 : &result);
1218 76 : if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1219 60 : r->out.domain_is_ad = true;
1220 60 : r->out.netbios_domain_name = info->dns.name.string;
1221 60 : r->out.dns_domain_name = info->dns.dns_domain.string;
1222 60 : r->out.forest_name = info->dns.dns_forest.string;
1223 60 : r->out.domain_guid = info->dns.domain_guid;
1224 60 : r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1225 60 : NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1226 : }
1227 :
1228 76 : if (!NT_STATUS_IS_OK(status)) {
1229 16 : status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1230 : &lsa_pol,
1231 : LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1232 : &info,
1233 : &result);
1234 16 : if (!NT_STATUS_IS_OK(status)) {
1235 0 : goto done;
1236 : }
1237 16 : if (!NT_STATUS_IS_OK(result)) {
1238 0 : status = result;
1239 0 : goto done;
1240 : }
1241 :
1242 16 : r->out.netbios_domain_name = info->account_domain.name.string;
1243 16 : r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1244 16 : NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1245 : }
1246 :
1247 76 : dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1248 76 : TALLOC_FREE(pipe_hnd);
1249 :
1250 0 : done:
1251 76 : return status;
1252 : }
1253 :
1254 : /****************************************************************
1255 : Do the domain join unsecure
1256 : ****************************************************************/
1257 :
1258 9 : static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1259 : struct libnet_JoinCtx *r,
1260 : struct cli_state *cli)
1261 : {
1262 9 : TALLOC_CTX *frame = talloc_stackframe();
1263 9 : struct rpc_pipe_client *authenticate_pipe = NULL;
1264 9 : struct rpc_pipe_client *passwordset_pipe = NULL;
1265 0 : struct cli_credentials *cli_creds;
1266 9 : struct netlogon_creds_cli_context *netlogon_creds = NULL;
1267 9 : struct netlogon_creds_CredentialState *creds = NULL;
1268 9 : uint32_t netlogon_flags = 0;
1269 9 : size_t len = 0;
1270 0 : bool ok;
1271 9 : DATA_BLOB new_trust_blob = data_blob_null;
1272 0 : NTSTATUS status;
1273 :
1274 9 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1275 : &authenticate_pipe);
1276 9 : if (!NT_STATUS_IS_OK(status)) {
1277 0 : TALLOC_FREE(frame);
1278 0 : return status;
1279 : }
1280 :
1281 9 : if (!r->in.machine_password) {
1282 9 : int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1283 :
1284 9 : r->in.machine_password = trust_pw_new_value(mem_ctx,
1285 : r->in.secure_channel_type,
1286 : security);
1287 9 : if (r->in.machine_password == NULL) {
1288 0 : TALLOC_FREE(frame);
1289 0 : return NT_STATUS_NO_MEMORY;
1290 : }
1291 : }
1292 :
1293 9 : cli_creds = cli_credentials_init(talloc_tos());
1294 9 : if (cli_creds == NULL) {
1295 0 : TALLOC_FREE(frame);
1296 0 : return NT_STATUS_NO_MEMORY;
1297 : }
1298 :
1299 9 : cli_credentials_set_username(cli_creds, r->out.account_name,
1300 : CRED_SPECIFIED);
1301 9 : cli_credentials_set_domain(cli_creds, r->in.domain_name,
1302 : CRED_SPECIFIED);
1303 9 : cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1304 9 : 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 9 : cli_credentials_set_password(cli_creds, r->in.admin_password,
1309 : CRED_SPECIFIED);
1310 :
1311 9 : status = rpccli_create_netlogon_creds_ctx(
1312 9 : cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
1313 : frame, &netlogon_creds);
1314 9 : if (!NT_STATUS_IS_OK(status)) {
1315 0 : TALLOC_FREE(frame);
1316 0 : return status;
1317 : }
1318 :
1319 9 : status = rpccli_setup_netlogon_creds(
1320 : cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
1321 : cli_creds);
1322 9 : if (!NT_STATUS_IS_OK(status)) {
1323 7 : TALLOC_FREE(frame);
1324 7 : return status;
1325 : }
1326 :
1327 2 : status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
1328 2 : if (!NT_STATUS_IS_OK(status)) {
1329 0 : TALLOC_FREE(frame);
1330 0 : return status;
1331 : }
1332 :
1333 2 : netlogon_flags = creds->negotiate_flags;
1334 2 : TALLOC_FREE(creds);
1335 :
1336 2 : if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1337 2 : const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1338 0 : const struct sockaddr_storage *remote_sockaddr =
1339 2 : smbXcli_conn_remote_sockaddr(cli->conn);
1340 :
1341 2 : 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 2 : 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 2 : len = strlen(r->in.machine_password);
1358 2 : ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1359 2 : r->in.machine_password, len,
1360 : &new_trust_blob.data,
1361 : &new_trust_blob.length);
1362 2 : 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 2 : status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1372 2 : passwordset_pipe->binding_handle,
1373 : &new_trust_blob,
1374 : NULL); /* new_version */
1375 2 : if (!NT_STATUS_IS_OK(status)) {
1376 0 : TALLOC_FREE(frame);
1377 0 : return status;
1378 : }
1379 :
1380 2 : TALLOC_FREE(frame);
1381 2 : return NT_STATUS_OK;
1382 : }
1383 :
1384 : /****************************************************************
1385 : Do the domain join
1386 : ****************************************************************/
1387 :
1388 7 : static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1389 : struct libnet_JoinCtx *r,
1390 : struct cli_state *cli)
1391 : {
1392 7 : struct rpc_pipe_client *pipe_hnd = NULL;
1393 0 : struct policy_handle sam_pol, domain_pol, user_pol;
1394 7 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1395 0 : char *acct_name;
1396 0 : struct lsa_String lsa_acct_name;
1397 7 : uint32_t acct_flags = ACB_WSTRUST;
1398 0 : struct samr_Ids user_rids;
1399 0 : struct samr_Ids name_types;
1400 0 : union samr_UserInfo user_info;
1401 7 : struct dcerpc_binding_handle *b = NULL;
1402 7 : unsigned int old_timeout = 0;
1403 :
1404 7 : DATA_BLOB session_key = data_blob_null;
1405 0 : struct samr_CryptPassword crypt_pwd;
1406 0 : struct samr_CryptPasswordEx crypt_pwd_ex;
1407 :
1408 7 : ZERO_STRUCT(sam_pol);
1409 7 : ZERO_STRUCT(domain_pol);
1410 7 : ZERO_STRUCT(user_pol);
1411 :
1412 7 : switch (r->in.secure_channel_type) {
1413 3 : case SEC_CHAN_WKSTA:
1414 3 : acct_flags = ACB_WSTRUST;
1415 3 : break;
1416 4 : case SEC_CHAN_BDC:
1417 4 : acct_flags = ACB_SVRTRUST;
1418 4 : break;
1419 0 : default:
1420 0 : return NT_STATUS_INVALID_PARAMETER;
1421 : }
1422 :
1423 7 : if (!r->in.machine_password) {
1424 7 : int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1425 :
1426 7 : r->in.machine_password = trust_pw_new_value(mem_ctx,
1427 : r->in.secure_channel_type,
1428 : security);
1429 7 : NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1430 : }
1431 :
1432 : /* Open the domain */
1433 :
1434 7 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1435 : &pipe_hnd);
1436 7 : 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 7 : b = pipe_hnd->binding_handle;
1443 :
1444 7 : status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1445 7 : 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 7 : status = dcerpc_samr_Connect2(b, mem_ctx,
1452 7 : pipe_hnd->desthost,
1453 : SAMR_ACCESS_ENUM_DOMAINS
1454 : | SAMR_ACCESS_LOOKUP_DOMAIN,
1455 : &sam_pol,
1456 : &result);
1457 7 : if (!NT_STATUS_IS_OK(status)) {
1458 0 : goto done;
1459 : }
1460 7 : if (!NT_STATUS_IS_OK(result)) {
1461 0 : status = result;
1462 0 : goto done;
1463 : }
1464 :
1465 7 : 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 7 : if (!NT_STATUS_IS_OK(status)) {
1474 0 : goto done;
1475 : }
1476 7 : if (!NT_STATUS_IS_OK(result)) {
1477 0 : status = result;
1478 0 : goto done;
1479 : }
1480 :
1481 : /* Create domain user */
1482 :
1483 7 : acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1484 7 : if (!strlower_m(acct_name)) {
1485 0 : status = NT_STATUS_INVALID_PARAMETER;
1486 0 : goto done;
1487 : }
1488 :
1489 7 : init_lsa_String(&lsa_acct_name, acct_name);
1490 :
1491 7 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1492 7 : 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 7 : uint32_t access_granted = 0;
1499 :
1500 7 : DEBUG(10,("Creating account with desired access mask: %d\n",
1501 : access_desired));
1502 :
1503 7 : 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 7 : if (!NT_STATUS_IS_OK(status)) {
1513 0 : goto done;
1514 : }
1515 :
1516 7 : status = result;
1517 7 : if (!NT_STATUS_IS_OK(status) &&
1518 2 : !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 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1537 2 : 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 7 : if (NT_STATUS_IS_OK(status)) {
1546 5 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1547 : }
1548 : }
1549 :
1550 7 : 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 7 : if (!NT_STATUS_IS_OK(status)) {
1558 0 : goto done;
1559 : }
1560 7 : if (!NT_STATUS_IS_OK(result)) {
1561 0 : status = result;
1562 0 : goto done;
1563 : }
1564 7 : if (user_rids.count != 1) {
1565 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1566 0 : goto done;
1567 : }
1568 7 : if (name_types.count != 1) {
1569 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1570 0 : goto done;
1571 : }
1572 :
1573 7 : 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 7 : r->out.account_rid = user_rids.ids[0];
1581 :
1582 : /* Open handle on user */
1583 :
1584 7 : 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 7 : if (!NT_STATUS_IS_OK(status)) {
1591 0 : goto done;
1592 : }
1593 7 : 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 7 : acct_flags |= ACB_PWNOEXP;
1601 :
1602 : /* Set account flags on machine account */
1603 7 : ZERO_STRUCT(user_info.info16);
1604 7 : user_info.info16.acct_flags = acct_flags;
1605 :
1606 7 : status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1607 : &user_pol,
1608 : UserControlInformation,
1609 : &user_info,
1610 : &result);
1611 7 : 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 7 : if (!NT_STATUS_IS_OK(result)) {
1623 0 : status = result;
1624 :
1625 0 : dcerpc_samr_DeleteUser(b, mem_ctx,
1626 : &user_pol,
1627 : &result);
1628 :
1629 0 : libnet_join_set_error_string(mem_ctx, r,
1630 : "Failed to set 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 7 : old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1642 :
1643 7 : status = init_samr_CryptPasswordEx(r->in.machine_password,
1644 : &session_key,
1645 : &crypt_pwd_ex);
1646 7 : if (!NT_STATUS_IS_OK(status)) {
1647 0 : goto error;
1648 : }
1649 :
1650 7 : user_info.info26.password = crypt_pwd_ex;
1651 7 : user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1652 :
1653 7 : status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1654 : &user_pol,
1655 : UserInternal5InformationNew,
1656 : &user_info,
1657 : &result);
1658 :
1659 7 : 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 7 : error:
1681 7 : old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1682 :
1683 7 : 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 7 : 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 7 : status = NT_STATUS_OK;
1708 :
1709 7 : done:
1710 7 : if (!pipe_hnd) {
1711 0 : return status;
1712 : }
1713 :
1714 7 : data_blob_clear_free(&session_key);
1715 :
1716 7 : if (is_valid_policy_hnd(&sam_pol)) {
1717 7 : dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1718 : }
1719 7 : if (is_valid_policy_hnd(&domain_pol)) {
1720 7 : dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1721 : }
1722 7 : if (is_valid_policy_hnd(&user_pol)) {
1723 7 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1724 : }
1725 7 : TALLOC_FREE(pipe_hnd);
1726 :
1727 7 : return status;
1728 : }
1729 :
1730 : /****************************************************************
1731 : ****************************************************************/
1732 :
1733 81 : 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 81 : TALLOC_CTX *frame = talloc_stackframe();
1739 81 : struct cli_state *cli = NULL;
1740 81 : struct rpc_pipe_client *netlogon_pipe = NULL;
1741 81 : struct cli_credentials *cli_creds = NULL;
1742 81 : struct netlogon_creds_cli_context *netlogon_creds = NULL;
1743 81 : struct netlogon_creds_CredentialState *creds = NULL;
1744 81 : uint32_t netlogon_flags = 0;
1745 0 : NTSTATUS status;
1746 81 : int flags = CLI_FULL_CONNECTION_IPC;
1747 81 : const char *remote_name = NULL;
1748 81 : const struct sockaddr_storage *remote_sockaddr = NULL;
1749 :
1750 81 : if (!dc_name) {
1751 0 : TALLOC_FREE(frame);
1752 0 : return NT_STATUS_INVALID_PARAMETER;
1753 : }
1754 :
1755 81 : if (!secrets_init()) {
1756 0 : TALLOC_FREE(frame);
1757 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1758 : }
1759 :
1760 81 : status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1761 : frame, &cli_creds);
1762 81 : 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 81 : cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1769 :
1770 81 : if (use_kerberos) {
1771 18 : cli_credentials_set_kerberos_state(cli_creds,
1772 : CRED_USE_KERBEROS_REQUIRED,
1773 : CRED_SPECIFIED);
1774 : }
1775 :
1776 81 : status = cli_full_connection_creds(&cli, NULL,
1777 : dc_name,
1778 : NULL, 0,
1779 : "IPC$", "IPC",
1780 : cli_creds,
1781 : flags);
1782 :
1783 81 : 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 81 : if (!NT_STATUS_IS_OK(status)) {
1802 0 : TALLOC_FREE(frame);
1803 0 : return status;
1804 : }
1805 :
1806 81 : status = rpccli_create_netlogon_creds_ctx(cli_creds,
1807 : dc_name,
1808 : msg_ctx,
1809 : frame,
1810 : &netlogon_creds);
1811 81 : if (!NT_STATUS_IS_OK(status)) {
1812 0 : cli_shutdown(cli);
1813 0 : TALLOC_FREE(frame);
1814 0 : return status;
1815 : }
1816 :
1817 81 : status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1818 : netlogon_creds,
1819 : true, /* force_reauth */
1820 : cli_creds);
1821 81 : 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 81 : status = netlogon_creds_cli_get(netlogon_creds,
1833 : talloc_tos(),
1834 : &creds);
1835 81 : if (!NT_STATUS_IS_OK(status)) {
1836 0 : cli_shutdown(cli);
1837 0 : TALLOC_FREE(frame);
1838 0 : return status;
1839 : }
1840 81 : netlogon_flags = creds->negotiate_flags;
1841 81 : TALLOC_FREE(creds);
1842 :
1843 81 : 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 81 : remote_name = smbXcli_conn_remote_name(cli->conn);
1850 81 : remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
1851 :
1852 81 : 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 81 : TALLOC_FREE(netlogon_pipe);
1860 :
1861 81 : 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 81 : cli_shutdown(cli);
1873 81 : TALLOC_FREE(frame);
1874 81 : return NT_STATUS_OK;
1875 : }
1876 :
1877 : /****************************************************************
1878 : ****************************************************************/
1879 :
1880 57 : static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1881 : struct libnet_JoinCtx *r)
1882 : {
1883 0 : NTSTATUS status;
1884 :
1885 57 : status = libnet_join_ok(r->in.msg_ctx,
1886 : r->out.netbios_domain_name,
1887 : r->in.dc_name,
1888 57 : r->in.use_kerberos);
1889 57 : 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 57 : return WERR_OK;
1897 : }
1898 :
1899 : /****************************************************************
1900 : ****************************************************************/
1901 :
1902 34 : 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 34 : return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1909 : }
1910 :
1911 : /****************************************************************
1912 : ****************************************************************/
1913 :
1914 4 : static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1915 : struct libnet_UnjoinCtx *r)
1916 : {
1917 4 : struct cli_state *cli = NULL;
1918 4 : struct rpc_pipe_client *pipe_hnd = NULL;
1919 0 : struct policy_handle sam_pol, domain_pol, user_pol;
1920 4 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1921 0 : char *acct_name;
1922 0 : uint32_t user_rid;
1923 0 : struct lsa_String lsa_acct_name;
1924 0 : struct samr_Ids user_rids;
1925 0 : struct samr_Ids name_types;
1926 4 : union samr_UserInfo *info = NULL;
1927 4 : struct dcerpc_binding_handle *b = NULL;
1928 :
1929 4 : ZERO_STRUCT(sam_pol);
1930 4 : ZERO_STRUCT(domain_pol);
1931 4 : ZERO_STRUCT(user_pol);
1932 :
1933 4 : 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 4 : r->in.use_kerberos,
1938 : &cli);
1939 4 : if (!NT_STATUS_IS_OK(status)) {
1940 2 : goto done;
1941 : }
1942 :
1943 : /* Open the domain */
1944 :
1945 2 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1946 : &pipe_hnd);
1947 2 : 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 2 : b = pipe_hnd->binding_handle;
1954 :
1955 2 : status = dcerpc_samr_Connect2(b, mem_ctx,
1956 2 : pipe_hnd->desthost,
1957 : SEC_FLAG_MAXIMUM_ALLOWED,
1958 : &sam_pol,
1959 : &result);
1960 2 : if (!NT_STATUS_IS_OK(status)) {
1961 0 : goto done;
1962 : }
1963 2 : if (!NT_STATUS_IS_OK(result)) {
1964 0 : status = result;
1965 0 : goto done;
1966 : }
1967 :
1968 2 : 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 2 : if (!NT_STATUS_IS_OK(status)) {
1975 0 : goto done;
1976 : }
1977 2 : if (!NT_STATUS_IS_OK(result)) {
1978 0 : status = result;
1979 0 : goto done;
1980 : }
1981 :
1982 : /* Create domain user */
1983 :
1984 2 : acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1985 2 : if (!strlower_m(acct_name)) {
1986 0 : status = NT_STATUS_INVALID_PARAMETER;
1987 0 : goto done;
1988 : }
1989 :
1990 2 : init_lsa_String(&lsa_acct_name, acct_name);
1991 :
1992 2 : 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 2 : if (!NT_STATUS_IS_OK(status)) {
2001 0 : goto done;
2002 : }
2003 2 : if (!NT_STATUS_IS_OK(result)) {
2004 0 : status = result;
2005 0 : goto done;
2006 : }
2007 2 : if (user_rids.count != 1) {
2008 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2009 0 : goto done;
2010 : }
2011 2 : if (name_types.count != 1) {
2012 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2013 0 : goto done;
2014 : }
2015 :
2016 2 : 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 2 : user_rid = user_rids.ids[0];
2024 :
2025 : /* Open handle on user */
2026 :
2027 2 : status = dcerpc_samr_OpenUser(b, mem_ctx,
2028 : &domain_pol,
2029 : SEC_FLAG_MAXIMUM_ALLOWED,
2030 : user_rid,
2031 : &user_pol,
2032 : &result);
2033 2 : if (!NT_STATUS_IS_OK(status)) {
2034 0 : goto done;
2035 : }
2036 2 : if (!NT_STATUS_IS_OK(result)) {
2037 0 : status = result;
2038 0 : goto done;
2039 : }
2040 :
2041 : /* Get user info */
2042 :
2043 2 : status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
2044 : &user_pol,
2045 : 16,
2046 : &info,
2047 : &result);
2048 2 : if (!NT_STATUS_IS_OK(status)) {
2049 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2050 0 : goto done;
2051 : }
2052 2 : 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 2 : info->info16.acct_flags |= ACB_DISABLED;
2061 :
2062 2 : status = dcerpc_samr_SetUserInfo(b, mem_ctx,
2063 : &user_pol,
2064 : 16,
2065 : info,
2066 : &result);
2067 2 : if (!NT_STATUS_IS_OK(status)) {
2068 0 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2069 0 : goto done;
2070 : }
2071 2 : 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 2 : status = result;
2077 2 : dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2078 :
2079 4 : done:
2080 4 : if (pipe_hnd && b) {
2081 2 : if (is_valid_policy_hnd(&domain_pol)) {
2082 2 : dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
2083 : }
2084 2 : if (is_valid_policy_hnd(&sam_pol)) {
2085 2 : dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
2086 : }
2087 2 : TALLOC_FREE(pipe_hnd);
2088 : }
2089 :
2090 4 : if (cli) {
2091 2 : cli_shutdown(cli);
2092 : }
2093 :
2094 4 : 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 0 : sbcErr err;
2104 0 : 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 0 : sbcErr err;
2178 0 : 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 75 : static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2212 : {
2213 0 : WERROR werr;
2214 :
2215 75 : if (!W_ERROR_IS_OK(r->out.result)) {
2216 0 : return r->out.result;
2217 : }
2218 :
2219 75 : if (!r->in.modify_config) {
2220 75 : 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 36 : static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2240 : {
2241 0 : WERROR werr;
2242 :
2243 36 : if (!W_ERROR_IS_OK(r->out.result)) {
2244 0 : return r->out.result;
2245 : }
2246 :
2247 36 : if (!r->in.modify_config) {
2248 36 : 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 136 : 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 136 : char *domain = NULL;
2273 136 : char *dc = NULL;
2274 136 : const char *p = NULL;
2275 :
2276 136 : if (!domain_str || !domain_p || !dc_p) {
2277 0 : return false;
2278 : }
2279 :
2280 136 : p = strchr_m(domain_str, '\\');
2281 :
2282 136 : 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 136 : domain = talloc_strdup(mem_ctx, domain_str);
2291 136 : dc = NULL;
2292 : }
2293 136 : if (!domain) {
2294 0 : return false;
2295 : }
2296 :
2297 136 : *domain_p = domain;
2298 :
2299 136 : if (!*dc_p && dc) {
2300 0 : *dc_p = dc;
2301 : }
2302 :
2303 136 : return true;
2304 : }
2305 :
2306 : /****************************************************************
2307 : ****************************************************************/
2308 :
2309 100 : static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2310 : struct libnet_JoinCtx *r)
2311 : {
2312 100 : 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 100 : 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 100 : r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2328 : r->in.machine_name);
2329 100 : 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 100 : 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 100 : 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 18 : return WERR_OK;
2349 : }
2350 :
2351 82 : if (!r->in.admin_domain) {
2352 78 : char *admin_domain = NULL;
2353 78 : char *admin_account = NULL;
2354 0 : bool ok;
2355 :
2356 78 : ok = split_domain_user(mem_ctx,
2357 : r->in.admin_account,
2358 : &admin_domain,
2359 : &admin_account);
2360 78 : if (!ok) {
2361 0 : return WERR_NOT_ENOUGH_MEMORY;
2362 : }
2363 :
2364 78 : if (admin_domain != NULL) {
2365 0 : r->in.admin_domain = admin_domain;
2366 : } else {
2367 78 : r->in.admin_domain = r->in.domain_name;
2368 : }
2369 78 : r->in.admin_account = admin_account;
2370 : }
2371 :
2372 82 : if (r->in.provision_computer_account_only) {
2373 : /*
2374 : * When in the "provision_computer_account_only" path we do not
2375 : * need to have access to secrets.tdb at all - gd
2376 : */
2377 12 : return WERR_OK;
2378 : }
2379 :
2380 70 : if (!secrets_init()) {
2381 0 : libnet_join_set_error_string(mem_ctx, r,
2382 : "Unable to open secrets database");
2383 0 : return WERR_CAN_NOT_COMPLETE;
2384 : }
2385 :
2386 70 : return WERR_OK;
2387 : }
2388 :
2389 : /****************************************************************
2390 : ****************************************************************/
2391 :
2392 75 : static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2393 : {
2394 0 : NTSTATUS status;
2395 :
2396 : /* Try adding dom admins to builtin\admins. Only log failures. */
2397 75 : status = create_builtin_administrators(domain_sid);
2398 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2399 23 : DEBUG(10,("Unable to auto-add domain administrators to "
2400 : "BUILTIN\\Administrators during join because "
2401 : "winbindd must be running.\n"));
2402 52 : } else if (!NT_STATUS_IS_OK(status)) {
2403 44 : DEBUG(5, ("Failed to auto-add domain administrators to "
2404 : "BUILTIN\\Administrators during join: %s\n",
2405 : nt_errstr(status)));
2406 : }
2407 :
2408 : /* Try adding dom users to builtin\users. Only log failures. */
2409 75 : status = create_builtin_users(domain_sid);
2410 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2411 23 : DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2412 : "during join because winbindd must be running.\n"));
2413 52 : } else if (!NT_STATUS_IS_OK(status)) {
2414 44 : DEBUG(5, ("Failed to auto-add domain administrators to "
2415 : "BUILTIN\\Administrators during join: %s\n",
2416 : nt_errstr(status)));
2417 : }
2418 :
2419 : /* Try adding dom guests to builtin\guests. Only log failures. */
2420 75 : status = create_builtin_guests(domain_sid);
2421 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2422 23 : DEBUG(10,("Unable to auto-add domain guests to "
2423 : "BUILTIN\\Guests during join because "
2424 : "winbindd must be running.\n"));
2425 52 : } else if (!NT_STATUS_IS_OK(status)) {
2426 44 : DEBUG(5, ("Failed to auto-add domain guests to "
2427 : "BUILTIN\\Guests during join: %s\n",
2428 : nt_errstr(status)));
2429 : }
2430 75 : }
2431 :
2432 : /****************************************************************
2433 : ****************************************************************/
2434 :
2435 87 : static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2436 : struct libnet_JoinCtx *r)
2437 : {
2438 0 : WERROR werr;
2439 :
2440 87 : if (!W_ERROR_IS_OK(r->out.result)) {
2441 0 : return r->out.result;
2442 : }
2443 :
2444 87 : if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2445 0 : werr = do_JoinConfig(r);
2446 0 : if (!W_ERROR_IS_OK(werr)) {
2447 0 : return werr;
2448 : }
2449 :
2450 0 : return WERR_OK;
2451 : }
2452 :
2453 : #ifdef HAVE_ADS
2454 83 : if (r->out.domain_is_ad &&
2455 78 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2456 0 : ADS_STATUS ads_status;
2457 :
2458 78 : ads_status = libnet_join_post_processing_ads_modify(mem_ctx, r);
2459 78 : if (!ADS_ERR_OK(ads_status)) {
2460 0 : return WERR_GEN_FAILURE;
2461 : }
2462 : }
2463 : #endif /* HAVE_ADS */
2464 :
2465 87 : if (r->in.provision_computer_account_only) {
2466 : /*
2467 : * When we only provision a computer account we are done here - gd.
2468 : */
2469 12 : return WERR_OK;
2470 : }
2471 :
2472 75 : saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2473 75 : if (r->out.dns_domain_name) {
2474 66 : saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2475 : }
2476 :
2477 75 : if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2478 0 : return WERR_NERR_SETUPNOTJOINED;
2479 : }
2480 :
2481 75 : werr = do_JoinConfig(r);
2482 75 : if (!W_ERROR_IS_OK(werr)) {
2483 0 : return werr;
2484 : }
2485 :
2486 : #ifdef HAVE_ADS
2487 71 : if (r->out.domain_is_ad &&
2488 66 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2489 0 : ADS_STATUS ads_status;
2490 :
2491 66 : ads_status = libnet_join_post_processing_ads_sync(mem_ctx, r);
2492 66 : if (!ADS_ERR_OK(ads_status)) {
2493 0 : return WERR_GEN_FAILURE;
2494 : }
2495 : }
2496 : #endif /* HAVE_ADS */
2497 :
2498 75 : libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2499 :
2500 75 : return WERR_OK;
2501 : }
2502 :
2503 : /****************************************************************
2504 : ****************************************************************/
2505 :
2506 104 : static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2507 : {
2508 104 : TALLOC_FREE(r->in.ads);
2509 :
2510 104 : return 0;
2511 : }
2512 :
2513 : /****************************************************************
2514 : ****************************************************************/
2515 :
2516 36 : static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2517 : {
2518 36 : TALLOC_FREE(r->in.ads);
2519 :
2520 36 : return 0;
2521 : }
2522 :
2523 : /****************************************************************
2524 : ****************************************************************/
2525 :
2526 104 : WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2527 : struct libnet_JoinCtx **r)
2528 : {
2529 0 : struct libnet_JoinCtx *ctx;
2530 :
2531 104 : ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2532 104 : if (!ctx) {
2533 0 : return WERR_NOT_ENOUGH_MEMORY;
2534 : }
2535 :
2536 104 : talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2537 :
2538 104 : ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2539 104 : W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2540 :
2541 104 : ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2542 :
2543 104 : ctx->in.desired_encryption_types = 0;
2544 104 : ctx->in.desired_encryption_types |= ENC_RC4_HMAC_MD5;
2545 104 : ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2546 104 : ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2547 :
2548 104 : *r = ctx;
2549 :
2550 104 : return WERR_OK;
2551 : }
2552 :
2553 : /****************************************************************
2554 : ****************************************************************/
2555 :
2556 36 : WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2557 : struct libnet_UnjoinCtx **r)
2558 : {
2559 0 : struct libnet_UnjoinCtx *ctx;
2560 :
2561 36 : ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2562 36 : if (!ctx) {
2563 0 : return WERR_NOT_ENOUGH_MEMORY;
2564 : }
2565 :
2566 36 : talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2567 :
2568 36 : ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2569 36 : W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2570 :
2571 36 : *r = ctx;
2572 :
2573 36 : return WERR_OK;
2574 : }
2575 :
2576 : /****************************************************************
2577 : ****************************************************************/
2578 :
2579 94 : static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2580 : struct libnet_JoinCtx *r)
2581 : {
2582 94 : bool valid_security = false;
2583 94 : bool valid_workgroup = false;
2584 94 : bool valid_realm = false;
2585 94 : bool valid_hostname = false;
2586 94 : bool ignored_realm = false;
2587 :
2588 : /* check if configuration is already set correctly */
2589 :
2590 94 : valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2591 94 : valid_hostname = strequal(lp_netbios_name(), r->in.machine_name);
2592 :
2593 94 : switch (r->out.domain_is_ad) {
2594 16 : case false:
2595 16 : valid_security = (lp_security() == SEC_DOMAIN)
2596 8 : || (lp_server_role() == ROLE_DOMAIN_PDC)
2597 24 : || (lp_server_role() == ROLE_DOMAIN_BDC);
2598 16 : if (valid_workgroup && valid_security) {
2599 : /* nothing to be done */
2600 16 : return WERR_OK;
2601 : }
2602 0 : break;
2603 78 : case true:
2604 78 : valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2605 78 : switch (lp_security()) {
2606 0 : case SEC_DOMAIN:
2607 0 : if (!valid_realm && lp_winbind_rpc_only()) {
2608 0 : valid_realm = true;
2609 0 : ignored_realm = true;
2610 : }
2611 :
2612 : FALL_THROUGH;
2613 : case SEC_ADS:
2614 78 : valid_security = true;
2615 : }
2616 :
2617 78 : if (valid_workgroup && valid_realm && valid_security &&
2618 : valid_hostname) {
2619 78 : if (ignored_realm && !r->in.modify_config)
2620 : {
2621 0 : libnet_join_set_error_string(mem_ctx, r,
2622 : "Warning: ignoring realm when "
2623 : "joining AD domain with "
2624 : "'security=domain' and "
2625 : "'winbind rpc only = yes'. "
2626 : "(realm set to '%s', "
2627 : "should be '%s').", lp_realm(),
2628 : r->out.dns_domain_name);
2629 : }
2630 : /* nothing to be done */
2631 78 : return WERR_OK;
2632 : }
2633 0 : break;
2634 : }
2635 :
2636 : /* check if we are supposed to manipulate configuration */
2637 :
2638 0 : if (!r->in.modify_config) {
2639 :
2640 0 : char *wrong_conf = talloc_strdup(mem_ctx, "");
2641 :
2642 0 : if (!valid_hostname) {
2643 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2644 : "\"netbios name\" set to '%s', should be '%s'",
2645 : lp_netbios_name(), r->in.machine_name);
2646 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2647 : }
2648 :
2649 0 : if (!valid_workgroup) {
2650 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2651 : "\"workgroup\" set to '%s', should be '%s'",
2652 : lp_workgroup(), r->out.netbios_domain_name);
2653 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2654 : }
2655 :
2656 0 : if (!valid_realm) {
2657 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2658 : "\"realm\" set to '%s', should be '%s'",
2659 : lp_realm(), r->out.dns_domain_name);
2660 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2661 : }
2662 :
2663 0 : if (!valid_security) {
2664 0 : const char *sec = NULL;
2665 0 : switch (lp_security()) {
2666 0 : case SEC_USER: sec = "user"; break;
2667 0 : case SEC_DOMAIN: sec = "domain"; break;
2668 0 : case SEC_ADS: sec = "ads"; break;
2669 : }
2670 0 : wrong_conf = talloc_asprintf_append(wrong_conf,
2671 : "\"security\" set to '%s', should be %s",
2672 0 : sec, r->out.domain_is_ad ?
2673 : "either 'domain' or 'ads'" : "'domain'");
2674 0 : W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2675 : }
2676 :
2677 0 : libnet_join_set_error_string(mem_ctx, r,
2678 : "Invalid configuration (%s) and configuration modification "
2679 : "was not requested", wrong_conf);
2680 0 : return WERR_CAN_NOT_COMPLETE;
2681 : }
2682 :
2683 : /* check if we are able to manipulate configuration */
2684 :
2685 0 : if (!lp_config_backend_is_registry()) {
2686 0 : libnet_join_set_error_string(mem_ctx, r,
2687 : "Configuration manipulation requested but not "
2688 : "supported by backend");
2689 0 : return WERR_NOT_SUPPORTED;
2690 : }
2691 :
2692 0 : return WERR_OK;
2693 : }
2694 :
2695 : /****************************************************************
2696 : ****************************************************************/
2697 :
2698 82 : static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2699 : struct libnet_JoinCtx *r)
2700 : {
2701 0 : NTSTATUS status;
2702 0 : WERROR werr;
2703 82 : struct cli_state *cli = NULL;
2704 : #ifdef HAVE_ADS
2705 0 : ADS_STATUS ads_status;
2706 : #endif /* HAVE_ADS */
2707 82 : const char *pre_connect_realm = NULL;
2708 82 : const char *sitename = NULL;
2709 0 : struct netr_DsRGetDCNameInfo *info;
2710 0 : const char *dc;
2711 82 : uint32_t name_type_flags = 0;
2712 :
2713 : /* Before contacting a DC, we can securely know
2714 : * the realm only if the user specifies it.
2715 : */
2716 82 : if (r->in.use_kerberos &&
2717 18 : r->in.domain_name_type == JoinDomNameTypeDNS) {
2718 18 : pre_connect_realm = r->in.domain_name;
2719 : }
2720 :
2721 82 : if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2722 50 : name_type_flags = DS_IS_DNS_NAME;
2723 32 : } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2724 4 : name_type_flags = DS_IS_FLAT_NAME;
2725 : }
2726 :
2727 82 : if (r->in.dc_name) {
2728 22 : status = dsgetonedcname(mem_ctx,
2729 : r->in.msg_ctx,
2730 : r->in.domain_name,
2731 : r->in.dc_name,
2732 : DS_DIRECTORY_SERVICE_REQUIRED |
2733 : DS_WRITABLE_REQUIRED |
2734 : DS_RETURN_DNS_NAME |
2735 : name_type_flags,
2736 : &info);
2737 : } else {
2738 60 : status = dsgetdcname(mem_ctx,
2739 : r->in.msg_ctx,
2740 : r->in.domain_name,
2741 : NULL,
2742 : NULL,
2743 : DS_FORCE_REDISCOVERY |
2744 : DS_DIRECTORY_SERVICE_REQUIRED |
2745 : DS_WRITABLE_REQUIRED |
2746 : DS_RETURN_DNS_NAME |
2747 : name_type_flags,
2748 : &info);
2749 : }
2750 82 : if (!NT_STATUS_IS_OK(status)) {
2751 6 : libnet_join_set_error_string(mem_ctx, r,
2752 : "failed to find DC for domain %s - %s",
2753 : r->in.domain_name,
2754 : get_friendly_nt_error_msg(status));
2755 6 : return WERR_NERR_DCNOTFOUND;
2756 : }
2757 :
2758 76 : dc = strip_hostname(info->dc_unc);
2759 76 : r->in.dc_name = talloc_strdup(mem_ctx, dc);
2760 76 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2761 :
2762 76 : if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2763 76 : info->dc_address[1] != '\\') {
2764 0 : DBG_ERR("ill-formed DC address '%s'\n",
2765 : info->dc_address);
2766 0 : return WERR_NERR_DCNOTFOUND;
2767 : }
2768 :
2769 76 : sitename = info->dc_site_name;
2770 : /* info goes out of scope but the memory stays
2771 : allocated on the talloc context */
2772 :
2773 : /* return the allocated netr_DsRGetDCNameInfo struct */
2774 76 : r->out.dcinfo = info;
2775 :
2776 76 : if (pre_connect_realm != NULL) {
2777 18 : struct sockaddr_storage ss = {0};
2778 18 : const char *numeric_dcip = info->dc_address + 2;
2779 :
2780 18 : if (numeric_dcip[0] == '\0') {
2781 0 : if (!interpret_string_addr(&ss, numeric_dcip,
2782 : AI_NUMERICHOST)) {
2783 0 : DBG_ERR(
2784 : "cannot parse IP address '%s' of DC '%s'\n",
2785 : numeric_dcip, r->in.dc_name);
2786 0 : return WERR_NERR_DCNOTFOUND;
2787 : }
2788 : } else {
2789 18 : if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2790 0 : DBG_WARNING(
2791 : "cannot resolve IP address of DC '%s'\n",
2792 : r->in.dc_name);
2793 0 : return WERR_NERR_DCNOTFOUND;
2794 : }
2795 : }
2796 :
2797 : /* The domain parameter is only used as modifier
2798 : * to krb5.conf file name. _JOIN_ is not a valid
2799 : * NetBIOS name so it cannot clash with another domain
2800 : * -- Uri.
2801 : */
2802 18 : create_local_private_krb5_conf_for_domain(pre_connect_realm,
2803 : "_JOIN_",
2804 : sitename,
2805 : &ss);
2806 : }
2807 :
2808 76 : status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2809 76 : if (!NT_STATUS_IS_OK(status)) {
2810 0 : libnet_join_set_error_string(mem_ctx, r,
2811 : "failed to lookup DC info for domain '%s' over rpc: %s",
2812 : r->in.domain_name, get_friendly_nt_error_msg(status));
2813 0 : return ntstatus_to_werror(status);
2814 : }
2815 :
2816 76 : werr = libnet_join_check_config(mem_ctx, r);
2817 76 : if (!W_ERROR_IS_OK(werr)) {
2818 0 : if (!r->in.provision_computer_account_only) {
2819 0 : goto done;
2820 : }
2821 : /* do not fail when only provisioning */
2822 : }
2823 :
2824 : #ifdef HAVE_ADS
2825 :
2826 69 : if (r->out.domain_is_ad) {
2827 60 : create_local_private_krb5_conf_for_domain(
2828 : r->out.dns_domain_name, r->out.netbios_domain_name,
2829 60 : sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2830 : }
2831 :
2832 69 : if (r->out.domain_is_ad &&
2833 60 : !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2834 :
2835 60 : const char *initial_account_ou = r->in.account_ou;
2836 :
2837 : /*
2838 : * we want to create the msDS-SupportedEncryptionTypes attribute
2839 : * as early as possible so always try an LDAP create as the user
2840 : * first. We copy r->in.account_ou because it may be changed
2841 : * during the machine pre-creation.
2842 : */
2843 :
2844 60 : ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2845 60 : if (!ADS_ERR_OK(ads_status)) {
2846 0 : libnet_join_set_error_string(mem_ctx, r,
2847 : "failed to connect to AD: %s",
2848 : ads_errstr(ads_status));
2849 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2850 : }
2851 :
2852 60 : ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2853 60 : if (ADS_ERR_OK(ads_status)) {
2854 :
2855 : /*
2856 : * LDAP object creation succeeded.
2857 : */
2858 60 : r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2859 :
2860 60 : return WERR_OK;
2861 : }
2862 :
2863 0 : if (initial_account_ou != NULL) {
2864 0 : libnet_join_set_error_string(mem_ctx, r,
2865 : "failed to precreate account in ou %s: %s",
2866 : r->in.account_ou,
2867 : ads_errstr(ads_status));
2868 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2869 : }
2870 :
2871 0 : DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2872 : r->in.account_ou, ads_errstr(ads_status));
2873 : }
2874 : #endif /* HAVE_ADS */
2875 :
2876 16 : if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2877 9 : (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2878 9 : status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2879 : } else {
2880 7 : status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2881 : }
2882 16 : if (!NT_STATUS_IS_OK(status)) {
2883 7 : libnet_join_set_error_string(mem_ctx, r,
2884 : "failed to join domain '%s' over rpc: %s",
2885 : r->in.domain_name, get_friendly_nt_error_msg(status));
2886 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2887 0 : return WERR_NERR_SETUPALREADYJOINED;
2888 : }
2889 7 : werr = ntstatus_to_werror(status);
2890 7 : goto done;
2891 : }
2892 :
2893 9 : werr = WERR_OK;
2894 :
2895 16 : done:
2896 16 : if (cli) {
2897 16 : cli_shutdown(cli);
2898 : }
2899 :
2900 16 : return werr;
2901 : }
2902 :
2903 : /****************************************************************
2904 : ****************************************************************/
2905 :
2906 18 : static WERROR libnet_DomainOfflineJoin(TALLOC_CTX *mem_ctx,
2907 : struct libnet_JoinCtx *r)
2908 : {
2909 0 : NTSTATUS status;
2910 0 : WERROR werr;
2911 0 : struct ODJ_WIN7BLOB win7blob;
2912 0 : struct OP_JOINPROV3_PART joinprov3;
2913 0 : const char *dc_name;
2914 :
2915 18 : if (!r->in.request_offline_join) {
2916 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
2917 : }
2918 :
2919 18 : if (r->in.odj_provision_data == NULL) {
2920 0 : return WERR_INVALID_PARAMETER;
2921 : }
2922 :
2923 18 : werr = libnet_odj_find_win7blob(r->in.odj_provision_data, &win7blob);
2924 18 : if (!W_ERROR_IS_OK(werr)) {
2925 0 : return werr;
2926 : }
2927 :
2928 18 : r->out.netbios_domain_name = talloc_strdup(mem_ctx,
2929 : win7blob.DnsDomainInfo.Name.string);
2930 18 : W_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
2931 :
2932 18 : r->out.dns_domain_name = talloc_strdup(mem_ctx,
2933 : win7blob.DnsDomainInfo.DnsDomainName.string);
2934 18 : W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2935 :
2936 18 : r->out.forest_name = talloc_strdup(mem_ctx,
2937 : win7blob.DnsDomainInfo.DnsForestName.string);
2938 18 : W_ERROR_HAVE_NO_MEMORY(r->out.forest_name);
2939 :
2940 18 : r->out.domain_guid = win7blob.DnsDomainInfo.DomainGuid;
2941 36 : r->out.domain_sid = dom_sid_dup(mem_ctx,
2942 18 : win7blob.DnsDomainInfo.Sid);
2943 18 : W_ERROR_HAVE_NO_MEMORY(r->out.domain_sid);
2944 :
2945 18 : werr = libnet_odj_find_joinprov3(r->in.odj_provision_data, &joinprov3);
2946 18 : if (!W_ERROR_IS_OK(werr)) {
2947 0 : return werr;
2948 : }
2949 :
2950 18 : r->out.account_rid = joinprov3.Rid;
2951 :
2952 18 : dc_name = strip_hostname(win7blob.DcInfo.dc_address);
2953 18 : if (dc_name == NULL) {
2954 0 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
2955 : }
2956 18 : r->in.dc_name = talloc_strdup(mem_ctx, dc_name);
2957 18 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2958 :
2959 18 : r->out.domain_is_ad = true;
2960 :
2961 : /* we cannot use talloc_steal but have to deep copy the struct here */
2962 18 : status = copy_netr_DsRGetDCNameInfo(mem_ctx, &win7blob.DcInfo,
2963 : &r->out.dcinfo);
2964 18 : if (!NT_STATUS_IS_OK(status)) {
2965 0 : return ntstatus_to_werror(status);
2966 : }
2967 :
2968 18 : werr = libnet_join_check_config(mem_ctx, r);
2969 18 : if (!W_ERROR_IS_OK(werr)) {
2970 0 : return werr;
2971 : }
2972 :
2973 18 : return WERR_OK;
2974 : #if 0
2975 : /* the following fields are currently not filled in */
2976 :
2977 : const char * dn;
2978 : uint32_t set_encryption_types;
2979 : const char * krb5_salt;
2980 : #endif
2981 : }
2982 :
2983 : /****************************************************************
2984 : ****************************************************************/
2985 :
2986 0 : static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2987 : struct libnet_JoinCtx *r)
2988 : {
2989 0 : WERROR werr;
2990 0 : struct libnet_UnjoinCtx *u = NULL;
2991 :
2992 0 : werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2993 0 : if (!W_ERROR_IS_OK(werr)) {
2994 0 : return werr;
2995 : }
2996 :
2997 0 : u->in.debug = r->in.debug;
2998 0 : u->in.dc_name = r->in.dc_name;
2999 0 : u->in.domain_name = r->in.domain_name;
3000 0 : u->in.admin_account = r->in.admin_account;
3001 0 : u->in.admin_password = r->in.admin_password;
3002 0 : u->in.modify_config = r->in.modify_config;
3003 0 : u->in.use_kerberos = r->in.use_kerberos;
3004 0 : u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
3005 : WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
3006 :
3007 0 : werr = libnet_Unjoin(mem_ctx, u);
3008 0 : TALLOC_FREE(u);
3009 :
3010 0 : return werr;
3011 : }
3012 :
3013 : /****************************************************************
3014 : ****************************************************************/
3015 :
3016 100 : WERROR libnet_Join(TALLOC_CTX *mem_ctx,
3017 : struct libnet_JoinCtx *r)
3018 : {
3019 0 : WERROR werr;
3020 :
3021 100 : if (r->in.debug) {
3022 92 : LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
3023 : }
3024 :
3025 100 : ZERO_STRUCT(r->out);
3026 :
3027 100 : werr = libnet_join_pre_processing(mem_ctx, r);
3028 100 : if (!W_ERROR_IS_OK(werr)) {
3029 0 : goto done;
3030 : }
3031 :
3032 100 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3033 100 : if (r->in.request_offline_join) {
3034 18 : werr = libnet_DomainOfflineJoin(mem_ctx, r);
3035 : } else {
3036 82 : werr = libnet_DomainJoin(mem_ctx, r);
3037 : }
3038 100 : if (!W_ERROR_IS_OK(werr)) {
3039 13 : goto done;
3040 : }
3041 : }
3042 :
3043 87 : werr = libnet_join_post_processing(mem_ctx, r);
3044 87 : if (!W_ERROR_IS_OK(werr)) {
3045 0 : goto done;
3046 : }
3047 :
3048 87 : if (r->in.provision_computer_account_only) {
3049 : /*
3050 : * When we only provision a computer account we are done here - gd.
3051 : */
3052 12 : goto done;
3053 : }
3054 :
3055 75 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3056 75 : if (r->in.request_offline_join) {
3057 : /*
3058 : * When we are serving an offline domain join request we
3059 : * have no network so we are done here - gd.
3060 : */
3061 18 : goto done;
3062 : }
3063 :
3064 57 : werr = libnet_join_post_verify(mem_ctx, r);
3065 57 : if (!W_ERROR_IS_OK(werr)) {
3066 0 : libnet_join_rollback(mem_ctx, r);
3067 : }
3068 : }
3069 :
3070 57 : done:
3071 100 : r->out.result = werr;
3072 :
3073 100 : if (r->in.debug) {
3074 92 : LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
3075 : }
3076 100 : return werr;
3077 : }
3078 :
3079 : /****************************************************************
3080 : ****************************************************************/
3081 :
3082 36 : static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
3083 : struct libnet_UnjoinCtx *r)
3084 : {
3085 0 : NTSTATUS status;
3086 :
3087 36 : if (!r->in.domain_sid) {
3088 0 : struct dom_sid sid;
3089 36 : if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
3090 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3091 : "Unable to fetch domain sid: are we joined?");
3092 0 : return WERR_NERR_SETUPNOTJOINED;
3093 : }
3094 36 : r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
3095 36 : W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
3096 : }
3097 :
3098 36 : if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
3099 0 : !r->in.delete_machine_account) {
3100 0 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3101 0 : return WERR_OK;
3102 : }
3103 :
3104 36 : if (!r->in.dc_name) {
3105 0 : struct netr_DsRGetDCNameInfo *info;
3106 0 : const char *dc;
3107 30 : status = dsgetdcname(mem_ctx,
3108 : r->in.msg_ctx,
3109 : r->in.domain_name,
3110 : NULL,
3111 : NULL,
3112 : DS_DIRECTORY_SERVICE_REQUIRED |
3113 : DS_WRITABLE_REQUIRED |
3114 : DS_RETURN_DNS_NAME,
3115 : &info);
3116 30 : if (!NT_STATUS_IS_OK(status)) {
3117 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3118 : "failed to find DC for domain %s - %s",
3119 : r->in.domain_name,
3120 : get_friendly_nt_error_msg(status));
3121 0 : return WERR_NERR_DCNOTFOUND;
3122 : }
3123 :
3124 30 : dc = strip_hostname(info->dc_unc);
3125 30 : r->in.dc_name = talloc_strdup(mem_ctx, dc);
3126 30 : W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
3127 : }
3128 :
3129 : #ifdef HAVE_ADS
3130 : /* for net ads leave, try to delete the account. If it works,
3131 : no sense in disabling. If it fails, we can still try to
3132 : disable it. jmcd */
3133 :
3134 36 : if (r->in.delete_machine_account) {
3135 0 : ADS_STATUS ads_status;
3136 34 : ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
3137 34 : if (ADS_ERR_OK(ads_status)) {
3138 : /* dirty hack */
3139 32 : r->out.dns_domain_name =
3140 32 : talloc_strdup(mem_ctx,
3141 32 : r->in.ads->server.realm);
3142 0 : ads_status =
3143 32 : libnet_unjoin_remove_machine_acct(mem_ctx, r);
3144 : }
3145 34 : if (!ADS_ERR_OK(ads_status)) {
3146 2 : libnet_unjoin_set_error_string(mem_ctx, r,
3147 : "failed to remove machine account from AD: %s",
3148 : ads_errstr(ads_status));
3149 : } else {
3150 32 : r->out.deleted_machine_account = true;
3151 32 : W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
3152 32 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3153 32 : return WERR_OK;
3154 : }
3155 : }
3156 : #endif /* HAVE_ADS */
3157 :
3158 : /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
3159 : "disable". */
3160 4 : if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
3161 4 : status = libnet_join_unjoindomain_rpc(mem_ctx, r);
3162 4 : if (!NT_STATUS_IS_OK(status)) {
3163 2 : libnet_unjoin_set_error_string(mem_ctx, r,
3164 : "failed to disable machine account via rpc: %s",
3165 : get_friendly_nt_error_msg(status));
3166 2 : if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
3167 0 : return WERR_NERR_SETUPNOTJOINED;
3168 : }
3169 2 : return ntstatus_to_werror(status);
3170 : }
3171 :
3172 2 : r->out.dns_domain_name = talloc_strdup(mem_ctx,
3173 : r->in.domain_name);
3174 2 : r->out.disabled_machine_account = true;
3175 : }
3176 :
3177 : /* If disable succeeded or was not requested at all, we
3178 : should be getting rid of our end of things */
3179 :
3180 2 : libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3181 :
3182 2 : return WERR_OK;
3183 : }
3184 :
3185 : /****************************************************************
3186 : ****************************************************************/
3187 :
3188 36 : static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
3189 : struct libnet_UnjoinCtx *r)
3190 : {
3191 36 : if (!r->in.domain_name) {
3192 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3193 : "No domain name defined");
3194 0 : return WERR_INVALID_PARAMETER;
3195 : }
3196 :
3197 36 : if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
3198 : &r->in.domain_name,
3199 : &r->in.dc_name)) {
3200 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3201 : "Failed to parse domain name");
3202 0 : return WERR_INVALID_PARAMETER;
3203 : }
3204 :
3205 36 : if (IS_DC) {
3206 0 : return WERR_NERR_SETUPDOMAINCONTROLLER;
3207 : }
3208 :
3209 36 : if (!r->in.admin_domain) {
3210 36 : char *admin_domain = NULL;
3211 36 : char *admin_account = NULL;
3212 0 : bool ok;
3213 :
3214 36 : ok = split_domain_user(mem_ctx,
3215 : r->in.admin_account,
3216 : &admin_domain,
3217 : &admin_account);
3218 36 : if (!ok) {
3219 0 : return WERR_NOT_ENOUGH_MEMORY;
3220 : }
3221 :
3222 36 : if (admin_domain != NULL) {
3223 0 : r->in.admin_domain = admin_domain;
3224 : } else {
3225 36 : r->in.admin_domain = r->in.domain_name;
3226 : }
3227 36 : r->in.admin_account = admin_account;
3228 : }
3229 :
3230 36 : if (!secrets_init()) {
3231 0 : libnet_unjoin_set_error_string(mem_ctx, r,
3232 : "Unable to open secrets database");
3233 0 : return WERR_CAN_NOT_COMPLETE;
3234 : }
3235 :
3236 36 : return WERR_OK;
3237 : }
3238 :
3239 : /****************************************************************
3240 : ****************************************************************/
3241 :
3242 34 : static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
3243 : struct libnet_UnjoinCtx *r)
3244 : {
3245 34 : saf_delete(r->out.netbios_domain_name);
3246 34 : saf_delete(r->out.dns_domain_name);
3247 :
3248 34 : return libnet_unjoin_config(r);
3249 : }
3250 :
3251 : /****************************************************************
3252 : ****************************************************************/
3253 :
3254 36 : WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
3255 : struct libnet_UnjoinCtx *r)
3256 : {
3257 0 : WERROR werr;
3258 :
3259 36 : if (r->in.debug) {
3260 34 : LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
3261 : }
3262 :
3263 36 : werr = libnet_unjoin_pre_processing(mem_ctx, r);
3264 36 : if (!W_ERROR_IS_OK(werr)) {
3265 0 : goto done;
3266 : }
3267 :
3268 36 : if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3269 36 : werr = libnet_DomainUnjoin(mem_ctx, r);
3270 36 : if (!W_ERROR_IS_OK(werr)) {
3271 2 : libnet_unjoin_config(r);
3272 2 : goto done;
3273 : }
3274 : }
3275 :
3276 34 : werr = libnet_unjoin_post_processing(mem_ctx, r);
3277 34 : if (!W_ERROR_IS_OK(werr)) {
3278 0 : goto done;
3279 : }
3280 :
3281 34 : done:
3282 36 : r->out.result = werr;
3283 :
3284 36 : if (r->in.debug) {
3285 34 : LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
3286 : }
3287 :
3288 36 : return werr;
3289 : }
|