s3:libnetapi: Return error from RequestOfflineJoin
[Samba.git] / source3 / lib / netapi / joindomain.c
blob7145ce5d6d1a0c1797e54290f05a29e900f8c07b
1 /*
2 * Unix SMB/CIFS implementation.
3 * NetApi Join Support
4 * Copyright (C) Guenther Deschner 2007-2008
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "ads.h"
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "libcli/auth/libcli_auth.h"
24 #include "lib/netapi/netapi.h"
25 #include "lib/netapi/netapi_private.h"
26 #include "lib/netapi/libnetapi.h"
27 #include "librpc/gen_ndr/libnet_join.h"
28 #include "libnet/libnet_join.h"
29 #include "../librpc/gen_ndr/ndr_wkssvc_c.h"
30 #include "rpc_client/cli_pipe.h"
31 #include "secrets.h"
32 #include "libsmb/dsgetdcname.h"
33 #include "../librpc/gen_ndr/ndr_ODJ.h"
34 #include "lib/util/base64.h"
35 #include "libnet/libnet_join_offline.h"
37 /****************************************************************
38 ****************************************************************/
40 WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
41 struct NetJoinDomain *r)
43 struct libnet_JoinCtx *j = NULL;
44 struct libnetapi_private_ctx *priv;
45 WERROR werr;
47 priv = talloc_get_type_abort(mem_ctx->private_data,
48 struct libnetapi_private_ctx);
50 if (!r->in.domain) {
51 return WERR_INVALID_PARAMETER;
54 werr = libnet_init_JoinCtx(mem_ctx, &j);
55 W_ERROR_NOT_OK_RETURN(werr);
57 j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
58 W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
60 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
61 NTSTATUS status;
62 struct netr_DsRGetDCNameInfo *info = NULL;
63 const char *dc = NULL;
64 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
65 DS_WRITABLE_REQUIRED |
66 DS_RETURN_DNS_NAME;
67 status = dsgetdcname(mem_ctx, priv->msg_ctx, r->in.domain,
68 NULL, NULL, flags, &info);
69 if (!NT_STATUS_IS_OK(status)) {
70 libnetapi_set_error_string(mem_ctx,
71 "%s", get_friendly_nt_error_msg(status));
72 return ntstatus_to_werror(status);
75 dc = strip_hostname(info->dc_unc);
76 j->in.dc_name = talloc_strdup(mem_ctx, dc);
77 W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
80 if (r->in.account_ou) {
81 j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
82 W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
85 if (r->in.account) {
86 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
87 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
90 if (r->in.password) {
91 j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
92 W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
95 j->in.join_flags = r->in.join_flags;
96 j->in.modify_config = true;
97 j->in.debug = true;
99 werr = libnet_Join(mem_ctx, j);
100 if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
101 libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
103 TALLOC_FREE(j);
105 return werr;
108 /****************************************************************
109 ****************************************************************/
111 WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
112 struct NetJoinDomain *r)
114 struct rpc_pipe_client *pipe_cli = NULL;
115 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
116 NTSTATUS status;
117 WERROR werr;
118 unsigned int old_timeout = 0;
119 struct dcerpc_binding_handle *b;
120 DATA_BLOB session_key;
122 if (IS_DC) {
123 return WERR_NERR_SETUPDOMAINCONTROLLER;
126 werr = libnetapi_open_pipe(ctx, r->in.server,
127 &ndr_table_wkssvc,
128 &pipe_cli);
129 if (!W_ERROR_IS_OK(werr)) {
130 goto done;
133 b = pipe_cli->binding_handle;
135 if (r->in.password) {
137 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
138 if (!NT_STATUS_IS_OK(status)) {
139 werr = ntstatus_to_werror(status);
140 goto done;
143 werr = encode_wkssvc_join_password_buffer(ctx,
144 r->in.password,
145 &session_key,
146 &encrypted_password);
147 if (!W_ERROR_IS_OK(werr)) {
148 goto done;
152 old_timeout = rpccli_set_timeout(pipe_cli, 600000);
154 status = dcerpc_wkssvc_NetrJoinDomain2(b, talloc_tos(),
155 r->in.server,
156 r->in.domain,
157 r->in.account_ou,
158 r->in.account,
159 encrypted_password,
160 r->in.join_flags,
161 &werr);
162 if (!NT_STATUS_IS_OK(status)) {
163 werr = ntstatus_to_werror(status);
164 goto done;
167 done:
168 if (pipe_cli && old_timeout) {
169 rpccli_set_timeout(pipe_cli, old_timeout);
172 return werr;
174 /****************************************************************
175 ****************************************************************/
177 WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
178 struct NetUnjoinDomain *r)
180 struct libnet_UnjoinCtx *u = NULL;
181 struct dom_sid domain_sid;
182 const char *domain = NULL;
183 WERROR werr;
184 struct libnetapi_private_ctx *priv;
185 const char *realm = lp_realm();
187 priv = talloc_get_type_abort(mem_ctx->private_data,
188 struct libnetapi_private_ctx);
190 if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
191 return WERR_NERR_SETUPNOTJOINED;
194 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
195 W_ERROR_NOT_OK_RETURN(werr);
197 if (realm[0] != '\0') {
198 domain = realm;
199 } else {
200 domain = lp_workgroup();
203 if (r->in.server_name) {
204 u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
205 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
206 } else {
207 NTSTATUS status;
208 struct netr_DsRGetDCNameInfo *info = NULL;
209 const char *dc = NULL;
210 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
211 DS_WRITABLE_REQUIRED |
212 DS_RETURN_DNS_NAME;
213 status = dsgetdcname(mem_ctx, priv->msg_ctx, domain,
214 NULL, NULL, flags, &info);
215 if (!NT_STATUS_IS_OK(status)) {
216 libnetapi_set_error_string(mem_ctx,
217 "failed to find DC for domain %s: %s",
218 domain,
219 get_friendly_nt_error_msg(status));
220 return ntstatus_to_werror(status);
223 dc = strip_hostname(info->dc_unc);
224 u->in.dc_name = talloc_strdup(mem_ctx, dc);
225 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
227 u->in.domain_name = domain;
230 if (r->in.account) {
231 u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
232 W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
235 if (r->in.password) {
236 u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
237 W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
240 u->in.domain_name = domain;
241 u->in.unjoin_flags = r->in.unjoin_flags;
242 u->in.delete_machine_account = false;
243 u->in.modify_config = true;
244 u->in.debug = true;
246 u->in.domain_sid = &domain_sid;
248 werr = libnet_Unjoin(mem_ctx, u);
249 if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
250 libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
252 TALLOC_FREE(u);
254 return werr;
257 /****************************************************************
258 ****************************************************************/
260 WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
261 struct NetUnjoinDomain *r)
263 struct rpc_pipe_client *pipe_cli = NULL;
264 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
265 NTSTATUS status;
266 WERROR werr;
267 unsigned int old_timeout = 0;
268 struct dcerpc_binding_handle *b;
269 DATA_BLOB session_key;
271 werr = libnetapi_open_pipe(ctx, r->in.server_name,
272 &ndr_table_wkssvc,
273 &pipe_cli);
274 if (!W_ERROR_IS_OK(werr)) {
275 goto done;
278 b = pipe_cli->binding_handle;
280 if (r->in.password) {
282 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
283 if (!NT_STATUS_IS_OK(status)) {
284 werr = ntstatus_to_werror(status);
285 goto done;
288 werr = encode_wkssvc_join_password_buffer(ctx,
289 r->in.password,
290 &session_key,
291 &encrypted_password);
292 if (!W_ERROR_IS_OK(werr)) {
293 goto done;
297 old_timeout = rpccli_set_timeout(pipe_cli, 60000);
299 status = dcerpc_wkssvc_NetrUnjoinDomain2(b, talloc_tos(),
300 r->in.server_name,
301 r->in.account,
302 encrypted_password,
303 r->in.unjoin_flags,
304 &werr);
305 if (!NT_STATUS_IS_OK(status)) {
306 werr = ntstatus_to_werror(status);
307 goto done;
310 done:
311 if (pipe_cli && old_timeout) {
312 rpccli_set_timeout(pipe_cli, old_timeout);
315 return werr;
318 /****************************************************************
319 ****************************************************************/
321 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
322 struct NetGetJoinInformation *r)
324 struct rpc_pipe_client *pipe_cli = NULL;
325 NTSTATUS status;
326 WERROR werr;
327 const char *buffer = NULL;
328 struct dcerpc_binding_handle *b;
330 werr = libnetapi_open_pipe(ctx, r->in.server_name,
331 &ndr_table_wkssvc,
332 &pipe_cli);
333 if (!W_ERROR_IS_OK(werr)) {
334 goto done;
337 b = pipe_cli->binding_handle;
339 status = dcerpc_wkssvc_NetrGetJoinInformation(b, talloc_tos(),
340 r->in.server_name,
341 &buffer,
342 (enum wkssvc_NetJoinStatus *)r->out.name_type,
343 &werr);
344 if (!NT_STATUS_IS_OK(status)) {
345 werr = ntstatus_to_werror(status);
346 goto done;
349 if (!W_ERROR_IS_OK(werr)) {
350 goto done;
353 *r->out.name_buffer = talloc_strdup(ctx, buffer);
354 W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
356 done:
357 return werr;
360 /****************************************************************
361 ****************************************************************/
363 WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
364 struct NetGetJoinInformation *r)
366 const char *realm = lp_realm();
368 if ((lp_security() == SEC_ADS) && realm[0] != '\0') {
369 *r->out.name_buffer = talloc_strdup(ctx, realm);
370 } else {
371 *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
373 if (!*r->out.name_buffer) {
374 return WERR_NOT_ENOUGH_MEMORY;
377 switch (lp_server_role()) {
378 case ROLE_DOMAIN_MEMBER:
379 case ROLE_DOMAIN_PDC:
380 case ROLE_DOMAIN_BDC:
381 case ROLE_IPA_DC:
382 *r->out.name_type = NetSetupDomainName;
383 break;
384 case ROLE_STANDALONE:
385 default:
386 *r->out.name_type = NetSetupWorkgroupName;
387 break;
390 return WERR_OK;
393 /****************************************************************
394 ****************************************************************/
396 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
397 struct NetGetJoinableOUs *r)
399 #ifdef HAVE_ADS
400 TALLOC_CTX *tmp_ctx = talloc_stackframe();
401 WERROR ret;
402 NTSTATUS status;
403 ADS_STATUS ads_status;
404 ADS_STRUCT *ads = NULL;
405 struct netr_DsRGetDCNameInfo *info = NULL;
406 const char *dc = NULL;
407 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
408 DS_RETURN_DNS_NAME;
409 struct libnetapi_private_ctx *priv;
410 char **p;
411 size_t s;
413 priv = talloc_get_type_abort(ctx->private_data,
414 struct libnetapi_private_ctx);
416 status = dsgetdcname(tmp_ctx, priv->msg_ctx, r->in.domain,
417 NULL, NULL, flags, &info);
418 if (!NT_STATUS_IS_OK(status)) {
419 libnetapi_set_error_string(ctx, "%s",
420 get_friendly_nt_error_msg(status));
421 ret = ntstatus_to_werror(status);
422 goto out;
425 dc = strip_hostname(info->dc_unc);
427 ads = ads_init(tmp_ctx,
428 info->domain_name,
429 info->domain_name,
431 ADS_SASL_PLAIN);
432 if (!ads) {
433 ret = WERR_GEN_FAILURE;
434 goto out;
437 ADS_TALLOC_CONST_FREE(ads->auth.user_name);
438 if (r->in.account) {
439 ads->auth.user_name = talloc_strdup(ads, r->in.account);
440 if (ads->auth.user_name == NULL) {
441 ret = WERR_NOT_ENOUGH_MEMORY;
442 goto out;
444 } else {
445 const char *username = NULL;
447 libnetapi_get_username(ctx, &username);
448 if (username != NULL) {
449 ads->auth.user_name = talloc_strdup(ads, username);
450 if (ads->auth.user_name == NULL) {
451 ret = WERR_NOT_ENOUGH_MEMORY;
452 goto out;
457 ADS_TALLOC_CONST_FREE(ads->auth.password);
458 if (r->in.password) {
459 ads->auth.password = talloc_strdup(ads, r->in.password);
460 if (ads->auth.password == NULL) {
461 ret = WERR_NOT_ENOUGH_MEMORY;
462 goto out;
464 } else {
465 const char *password = NULL;
467 libnetapi_get_password(ctx, &password);
468 if (password != NULL) {
469 ads->auth.password = talloc_strdup(ads, password);
470 if (ads->auth.password == NULL) {
471 ret = WERR_NOT_ENOUGH_MEMORY;
472 goto out;
477 ads_status = ads_connect_user_creds(ads);
478 if (!ADS_ERR_OK(ads_status)) {
479 ret = WERR_NERR_DEFAULTJOINREQUIRED;
480 goto out;
483 ads_status = ads_get_joinable_ous(ads, ctx, &p, &s);
484 if (!ADS_ERR_OK(ads_status)) {
485 ret = WERR_NERR_DEFAULTJOINREQUIRED;
486 goto out;
488 *r->out.ous = discard_const_p(const char *, p);
489 *r->out.ou_count = s;
491 ret = WERR_OK;
492 out:
493 TALLOC_FREE(tmp_ctx);
495 return ret;
496 #else
497 return WERR_NOT_SUPPORTED;
498 #endif
501 /****************************************************************
502 ****************************************************************/
504 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
505 struct NetGetJoinableOUs *r)
507 struct rpc_pipe_client *pipe_cli = NULL;
508 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
509 NTSTATUS status;
510 WERROR werr;
511 struct dcerpc_binding_handle *b;
512 DATA_BLOB session_key;
514 werr = libnetapi_open_pipe(ctx, r->in.server_name,
515 &ndr_table_wkssvc,
516 &pipe_cli);
517 if (!W_ERROR_IS_OK(werr)) {
518 goto done;
521 b = pipe_cli->binding_handle;
523 if (r->in.password) {
525 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
526 if (!NT_STATUS_IS_OK(status)) {
527 werr = ntstatus_to_werror(status);
528 goto done;
531 werr = encode_wkssvc_join_password_buffer(ctx,
532 r->in.password,
533 &session_key,
534 &encrypted_password);
535 if (!W_ERROR_IS_OK(werr)) {
536 goto done;
540 status = dcerpc_wkssvc_NetrGetJoinableOus2(b, talloc_tos(),
541 r->in.server_name,
542 r->in.domain,
543 r->in.account,
544 encrypted_password,
545 r->out.ou_count,
546 r->out.ous,
547 &werr);
548 if (!NT_STATUS_IS_OK(status)) {
549 werr = ntstatus_to_werror(status);
550 goto done;
553 done:
554 return werr;
557 /****************************************************************
558 ****************************************************************/
560 WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
561 struct NetRenameMachineInDomain *r)
563 struct rpc_pipe_client *pipe_cli = NULL;
564 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
565 NTSTATUS status;
566 WERROR werr;
567 struct dcerpc_binding_handle *b;
568 DATA_BLOB session_key;
570 werr = libnetapi_open_pipe(ctx, r->in.server_name,
571 &ndr_table_wkssvc,
572 &pipe_cli);
573 if (!W_ERROR_IS_OK(werr)) {
574 goto done;
577 b = pipe_cli->binding_handle;
579 if (r->in.password) {
581 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
582 if (!NT_STATUS_IS_OK(status)) {
583 werr = ntstatus_to_werror(status);
584 goto done;
587 werr = encode_wkssvc_join_password_buffer(ctx,
588 r->in.password,
589 &session_key,
590 &encrypted_password);
591 if (!W_ERROR_IS_OK(werr)) {
592 goto done;
596 status = dcerpc_wkssvc_NetrRenameMachineInDomain2(b, talloc_tos(),
597 r->in.server_name,
598 r->in.new_machine_name,
599 r->in.account,
600 encrypted_password,
601 r->in.rename_options,
602 &werr);
603 if (!NT_STATUS_IS_OK(status)) {
604 werr = ntstatus_to_werror(status);
605 goto done;
608 done:
609 return werr;
612 /****************************************************************
613 ****************************************************************/
615 WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
616 struct NetRenameMachineInDomain *r)
618 LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
621 /****************************************************************
622 ****************************************************************/
624 WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
625 struct NetProvisionComputerAccount *r)
627 return NetProvisionComputerAccount_l(ctx, r);
630 /****************************************************************
631 ****************************************************************/
633 static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
634 struct NetProvisionComputerAccount *r,
635 TALLOC_CTX *mem_ctx,
636 struct ODJ_PROVISION_DATA **p)
638 WERROR werr;
639 struct libnet_JoinCtx *j = NULL;
640 int use_kerberos = 0;
641 const char *username = NULL;
643 werr = libnet_init_JoinCtx(mem_ctx, &j);
644 if (!W_ERROR_IS_OK(werr)) {
645 return werr;
648 j->in.domain_name = talloc_strdup(j, r->in.domain);
649 if (j->in.domain_name == NULL) {
650 talloc_free(j);
651 return WERR_NOT_ENOUGH_MEMORY;
654 talloc_free(discard_const_p(char *, j->in.machine_name));
655 j->in.machine_name = talloc_strdup(j, r->in.machine_name);
656 if (j->in.machine_name == NULL) {
657 talloc_free(j);
658 return WERR_NOT_ENOUGH_MEMORY;
661 if (r->in.dcname) {
662 j->in.dc_name = talloc_strdup(j, r->in.dcname);
663 if (j->in.dc_name == NULL) {
664 talloc_free(j);
665 return WERR_NOT_ENOUGH_MEMORY;
669 if (r->in.machine_account_ou) {
670 j->in.account_ou = talloc_strdup(j, r->in.machine_account_ou);
671 if (j->in.account_ou == NULL) {
672 talloc_free(j);
673 return WERR_NOT_ENOUGH_MEMORY;
677 libnetapi_get_username(ctx, &username);
678 if (username == NULL) {
679 talloc_free(j);
680 return WERR_NERR_BADUSERNAME;
683 j->in.admin_account = talloc_strdup(j, username);
684 if (j->in.admin_account == NULL) {
685 talloc_free(j);
686 return WERR_NOT_ENOUGH_MEMORY;
689 libnetapi_get_use_kerberos(ctx, &use_kerberos);
690 if (!use_kerberos) {
691 const char *password = NULL;
693 libnetapi_get_password(ctx, &password);
694 if (password == NULL) {
695 talloc_free(j);
696 return WERR_NERR_BADPASSWORD;
698 j->in.admin_password = talloc_strdup(j, password);
699 if (j->in.admin_password == NULL) {
700 talloc_free(j);
701 return WERR_NOT_ENOUGH_MEMORY;
705 j->in.use_kerberos = use_kerberos;
706 j->in.debug = true;
707 j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
708 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
710 if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
711 j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
714 if (r->in.options & NETSETUP_PROVISION_USE_DEFAULT_PASSWORD) {
715 j->in.join_flags |= WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
716 j->in.machine_password = talloc_strdup(j, r->in.machine_name);
717 if (j->in.machine_password == NULL) {
718 talloc_free(j);
719 return WERR_NOT_ENOUGH_MEMORY;
723 j->in.provision_computer_account_only = true;
725 werr = libnet_Join(mem_ctx, j);
726 if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
727 libnetapi_set_error_string(ctx, "%s", j->out.error_string);
728 talloc_free(j);
729 return werr;
732 werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
733 if (!W_ERROR_IS_OK(werr)) {
734 talloc_free(j);
735 return werr;
738 TALLOC_FREE(j);
740 return WERR_OK;
743 WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
744 struct NetProvisionComputerAccount *r)
746 WERROR werr;
747 enum ndr_err_code ndr_err;
748 const char *b64_bin_data_str;
749 DATA_BLOB blob;
750 struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
751 struct ODJ_PROVISION_DATA *p;
752 TALLOC_CTX *mem_ctx = talloc_new(ctx);
754 if (r->in.provision_bin_data == NULL &&
755 r->in.provision_text_data == NULL) {
756 return WERR_INVALID_PARAMETER;
758 if (r->in.provision_bin_data != NULL &&
759 r->in.provision_text_data != NULL) {
760 return WERR_INVALID_PARAMETER;
762 if (r->in.provision_bin_data == NULL &&
763 r->in.provision_bin_data_size != NULL) {
764 return WERR_INVALID_PARAMETER;
766 if (r->in.provision_bin_data != NULL &&
767 r->in.provision_bin_data_size == NULL) {
768 return WERR_INVALID_PARAMETER;
771 if (r->in.domain == NULL) {
772 return WERR_INVALID_PARAMETER;
775 if (r->in.machine_name == NULL) {
776 return WERR_INVALID_PARAMETER;
779 werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
780 if (!W_ERROR_IS_OK(werr)) {
781 talloc_free(mem_ctx);
782 return werr;
785 ZERO_STRUCT(odj_provision_data);
787 odj_provision_data.s.p = p;
789 ndr_err = ndr_push_struct_blob(&blob, ctx, &odj_provision_data,
790 (ndr_push_flags_fn_t)ndr_push_ODJ_PROVISION_DATA_serialized_ptr);
791 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
792 talloc_free(mem_ctx);
793 return W_ERROR(NERR_BadOfflineJoinInfo);
796 talloc_free(mem_ctx);
798 if (r->out.provision_text_data != NULL) {
799 b64_bin_data_str = base64_encode_data_blob(ctx, blob);
800 if (b64_bin_data_str == NULL) {
801 return WERR_NOT_ENOUGH_MEMORY;
803 *r->out.provision_text_data = b64_bin_data_str;
806 if (r->out.provision_bin_data != NULL &&
807 r->out.provision_bin_data_size != NULL) {
808 *r->out.provision_bin_data = blob.data;
809 *r->out.provision_bin_data_size = blob.length;
812 return werr;
815 /****************************************************************
816 ****************************************************************/
818 WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
819 struct NetRequestOfflineDomainJoin *r)
821 return WERR_NOT_SUPPORTED;
824 /****************************************************************
825 ****************************************************************/
827 static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
828 const struct ODJ_WIN7BLOB *win7blob,
829 const struct ODJ_PROVISION_DATA *odj_provision_data)
831 struct libnet_JoinCtx *j = NULL;
832 WERROR werr;
834 werr = libnet_init_JoinCtx(ctx, &j);
835 if (!W_ERROR_IS_OK(werr)) {
836 return werr;
839 j->in.domain_name = talloc_strdup(j, win7blob->lpDomain);
840 if (j->in.domain_name == NULL) {
841 talloc_free(j);
842 return WERR_NOT_ENOUGH_MEMORY;
845 talloc_free(discard_const_p(char *, j->in.machine_name));
846 j->in.machine_name = talloc_strdup(j, win7blob->lpMachineName);
847 if (j->in.machine_name == NULL) {
848 talloc_free(j);
849 return WERR_NOT_ENOUGH_MEMORY;
852 j->in.machine_password = talloc_strdup(j, win7blob->lpMachinePassword);
853 if (j->in.machine_password == NULL) {
854 talloc_free(j);
855 return WERR_NOT_ENOUGH_MEMORY;
858 j->in.request_offline_join = true;
859 j->in.odj_provision_data = discard_const(odj_provision_data);
860 j->in.debug = true;
861 j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
862 WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
864 werr = libnet_Join(j, j);
865 if (!W_ERROR_IS_OK(werr)) {
866 if (j->out.error_string != NULL) {
867 libnetapi_set_error_string(ctx, "%s", j->out.error_string);
869 talloc_free(j);
870 return werr;
873 TALLOC_FREE(j);
875 return WERR_OK;
878 WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
879 struct NetRequestOfflineDomainJoin *r)
881 DATA_BLOB blob, blob_base64;
882 enum ndr_err_code ndr_err;
883 struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
884 bool ok;
885 struct ODJ_WIN7BLOB win7blob = { 0 };
886 WERROR werr;
888 if (r->in.provision_bin_data == NULL ||
889 r->in.provision_bin_data_size == 0) {
890 return W_ERROR(NERR_NoOfflineJoinInfo);
893 if (r->in.provision_bin_data_size < 2) {
894 return W_ERROR(NERR_BadOfflineJoinInfo);
897 if (r->in.provision_bin_data[0] == 0xff &&
898 r->in.provision_bin_data[1] == 0xfe) {
899 ok = convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX,
900 r->in.provision_bin_data+2,
901 r->in.provision_bin_data_size-2,
902 &blob_base64.data,
903 &blob_base64.length);
904 if (!ok) {
905 return W_ERROR(NERR_BadOfflineJoinInfo);
907 } else {
908 blob_base64 = data_blob(r->in.provision_bin_data,
909 r->in.provision_bin_data_size);
912 blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
914 ndr_err = ndr_pull_struct_blob(&blob, ctx, &odj_provision_data,
915 (ndr_pull_flags_fn_t)ndr_pull_ODJ_PROVISION_DATA_serialized_ptr);
916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
917 return W_ERROR(NERR_BadOfflineJoinInfo);
920 if (DEBUGLEVEL >= 10) {
921 NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
924 if (odj_provision_data.s.p->ulVersion != 1) {
925 return W_ERROR(NERR_ProvisioningBlobUnsupported);
928 werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
929 if (!W_ERROR_IS_OK(werr)) {
930 return werr;
933 if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
934 return WERR_NERR_SETUPNOTJOINED;
937 werr = NetRequestOfflineDomainJoin_backend(ctx,
938 &win7blob,
939 odj_provision_data.s.p);
940 if (!W_ERROR_IS_OK(werr)) {
941 return werr;
944 return W_ERROR(NERR_JoinPerformedMustRestart);