2 * Unix SMB/CIFS implementation.
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/>.
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"
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;
47 priv = talloc_get_type_abort(mem_ctx->private_data,
48 struct libnetapi_private_ctx);
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) {
62 struct netr_DsRGetDCNameInfo *info = NULL;
63 const char *dc = NULL;
64 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
65 DS_WRITABLE_REQUIRED |
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);
86 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
87 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
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;
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);
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;
118 unsigned int old_timeout = 0;
119 struct dcerpc_binding_handle *b;
120 DATA_BLOB session_key;
123 return WERR_NERR_SETUPDOMAINCONTROLLER;
126 werr = libnetapi_open_pipe(ctx, r->in.server,
129 if (!W_ERROR_IS_OK(werr)) {
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);
143 werr = encode_wkssvc_join_password_buffer(ctx,
146 &encrypted_password);
147 if (!W_ERROR_IS_OK(werr)) {
152 old_timeout = rpccli_set_timeout(pipe_cli, 600000);
154 status = dcerpc_wkssvc_NetrJoinDomain2(b, talloc_tos(),
162 if (!NT_STATUS_IS_OK(status)) {
163 werr = ntstatus_to_werror(status);
168 if (pipe_cli && old_timeout) {
169 rpccli_set_timeout(pipe_cli, old_timeout);
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;
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') {
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);
208 struct netr_DsRGetDCNameInfo *info = NULL;
209 const char *dc = NULL;
210 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
211 DS_WRITABLE_REQUIRED |
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",
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;
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;
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);
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;
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,
274 if (!W_ERROR_IS_OK(werr)) {
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);
288 werr = encode_wkssvc_join_password_buffer(ctx,
291 &encrypted_password);
292 if (!W_ERROR_IS_OK(werr)) {
297 old_timeout = rpccli_set_timeout(pipe_cli, 60000);
299 status = dcerpc_wkssvc_NetrUnjoinDomain2(b, talloc_tos(),
305 if (!NT_STATUS_IS_OK(status)) {
306 werr = ntstatus_to_werror(status);
311 if (pipe_cli && old_timeout) {
312 rpccli_set_timeout(pipe_cli, old_timeout);
318 /****************************************************************
319 ****************************************************************/
321 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
322 struct NetGetJoinInformation *r)
324 struct rpc_pipe_client *pipe_cli = NULL;
327 const char *buffer = NULL;
328 struct dcerpc_binding_handle *b;
330 werr = libnetapi_open_pipe(ctx, r->in.server_name,
333 if (!W_ERROR_IS_OK(werr)) {
337 b = pipe_cli->binding_handle;
339 status = dcerpc_wkssvc_NetrGetJoinInformation(b, talloc_tos(),
342 (enum wkssvc_NetJoinStatus *)r->out.name_type,
344 if (!NT_STATUS_IS_OK(status)) {
345 werr = ntstatus_to_werror(status);
349 if (!W_ERROR_IS_OK(werr)) {
353 *r->out.name_buffer = talloc_strdup(ctx, buffer);
354 W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
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);
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:
382 *r->out.name_type = NetSetupDomainName;
384 case ROLE_STANDALONE:
386 *r->out.name_type = NetSetupWorkgroupName;
393 /****************************************************************
394 ****************************************************************/
396 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
397 struct NetGetJoinableOUs *r)
400 TALLOC_CTX *tmp_ctx = talloc_stackframe();
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 |
409 struct libnetapi_private_ctx *priv;
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);
425 dc = strip_hostname(info->dc_unc);
427 ads = ads_init(tmp_ctx,
433 ret = WERR_GEN_FAILURE;
437 SAFE_FREE(ads->auth.user_name);
439 ads->auth.user_name = SMB_STRDUP(r->in.account);
441 const char *username = NULL;
443 libnetapi_get_username(ctx, &username);
444 if (username != NULL) {
445 ads->auth.user_name = SMB_STRDUP(username);
449 TALLOC_FREE(ads->auth.password);
450 if (r->in.password) {
451 ads->auth.password = talloc_strdup(ads, r->in.password);
452 if (ads->auth.password == NULL) {
453 ret = WERR_NOT_ENOUGH_MEMORY;
457 const char *password = NULL;
459 libnetapi_get_password(ctx, &password);
460 if (password != NULL) {
461 ads->auth.password = talloc_strdup(ads, password);
462 if (ads->auth.password == NULL) {
463 ret = WERR_NOT_ENOUGH_MEMORY;
469 ads_status = ads_connect_user_creds(ads);
470 if (!ADS_ERR_OK(ads_status)) {
471 ret = WERR_NERR_DEFAULTJOINREQUIRED;
475 ads_status = ads_get_joinable_ous(ads, ctx, &p, &s);
476 if (!ADS_ERR_OK(ads_status)) {
477 ret = WERR_NERR_DEFAULTJOINREQUIRED;
480 *r->out.ous = discard_const_p(const char *, p);
481 *r->out.ou_count = s;
485 TALLOC_FREE(tmp_ctx);
489 return WERR_NOT_SUPPORTED;
493 /****************************************************************
494 ****************************************************************/
496 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
497 struct NetGetJoinableOUs *r)
499 struct rpc_pipe_client *pipe_cli = NULL;
500 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
503 struct dcerpc_binding_handle *b;
504 DATA_BLOB session_key;
506 werr = libnetapi_open_pipe(ctx, r->in.server_name,
509 if (!W_ERROR_IS_OK(werr)) {
513 b = pipe_cli->binding_handle;
515 if (r->in.password) {
517 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
518 if (!NT_STATUS_IS_OK(status)) {
519 werr = ntstatus_to_werror(status);
523 werr = encode_wkssvc_join_password_buffer(ctx,
526 &encrypted_password);
527 if (!W_ERROR_IS_OK(werr)) {
532 status = dcerpc_wkssvc_NetrGetJoinableOus2(b, talloc_tos(),
540 if (!NT_STATUS_IS_OK(status)) {
541 werr = ntstatus_to_werror(status);
549 /****************************************************************
550 ****************************************************************/
552 WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
553 struct NetRenameMachineInDomain *r)
555 struct rpc_pipe_client *pipe_cli = NULL;
556 struct wkssvc_PasswordBuffer *encrypted_password = NULL;
559 struct dcerpc_binding_handle *b;
560 DATA_BLOB session_key;
562 werr = libnetapi_open_pipe(ctx, r->in.server_name,
565 if (!W_ERROR_IS_OK(werr)) {
569 b = pipe_cli->binding_handle;
571 if (r->in.password) {
573 status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
574 if (!NT_STATUS_IS_OK(status)) {
575 werr = ntstatus_to_werror(status);
579 werr = encode_wkssvc_join_password_buffer(ctx,
582 &encrypted_password);
583 if (!W_ERROR_IS_OK(werr)) {
588 status = dcerpc_wkssvc_NetrRenameMachineInDomain2(b, talloc_tos(),
590 r->in.new_machine_name,
593 r->in.rename_options,
595 if (!NT_STATUS_IS_OK(status)) {
596 werr = ntstatus_to_werror(status);
604 /****************************************************************
605 ****************************************************************/
607 WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
608 struct NetRenameMachineInDomain *r)
610 LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
613 /****************************************************************
614 ****************************************************************/
616 WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
617 struct NetProvisionComputerAccount *r)
619 return NetProvisionComputerAccount_l(ctx, r);
622 /****************************************************************
623 ****************************************************************/
625 static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
626 struct NetProvisionComputerAccount *r,
628 struct ODJ_PROVISION_DATA **p)
631 struct libnet_JoinCtx *j = NULL;
632 int use_kerberos = 0;
633 const char *username = NULL;
635 werr = libnet_init_JoinCtx(mem_ctx, &j);
636 if (!W_ERROR_IS_OK(werr)) {
640 j->in.domain_name = talloc_strdup(j, r->in.domain);
641 if (j->in.domain_name == NULL) {
643 return WERR_NOT_ENOUGH_MEMORY;
646 talloc_free(discard_const_p(char *, j->in.machine_name));
647 j->in.machine_name = talloc_strdup(j, r->in.machine_name);
648 if (j->in.machine_name == NULL) {
650 return WERR_NOT_ENOUGH_MEMORY;
654 j->in.dc_name = talloc_strdup(j, r->in.dcname);
655 if (j->in.dc_name == NULL) {
657 return WERR_NOT_ENOUGH_MEMORY;
661 if (r->in.machine_account_ou) {
662 j->in.account_ou = talloc_strdup(j, r->in.machine_account_ou);
663 if (j->in.account_ou == NULL) {
665 return WERR_NOT_ENOUGH_MEMORY;
669 libnetapi_get_username(ctx, &username);
670 if (username == NULL) {
672 return WERR_NERR_BADUSERNAME;
675 j->in.admin_account = talloc_strdup(j, username);
676 if (j->in.admin_account == NULL) {
678 return WERR_NOT_ENOUGH_MEMORY;
681 libnetapi_get_use_kerberos(ctx, &use_kerberos);
683 const char *password = NULL;
685 libnetapi_get_password(ctx, &password);
686 if (password == NULL) {
688 return WERR_NERR_BADPASSWORD;
690 j->in.admin_password = talloc_strdup(j, password);
691 if (j->in.admin_password == NULL) {
693 return WERR_NOT_ENOUGH_MEMORY;
697 j->in.use_kerberos = use_kerberos;
699 j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
700 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
702 if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
703 j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
706 if (r->in.options & NETSETUP_PROVISION_USE_DEFAULT_PASSWORD) {
707 j->in.join_flags |= WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
708 j->in.machine_password = talloc_strdup(j, r->in.machine_name);
709 if (j->in.machine_password == NULL) {
711 return WERR_NOT_ENOUGH_MEMORY;
715 j->in.provision_computer_account_only = true;
717 werr = libnet_Join(mem_ctx, j);
718 if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
719 libnetapi_set_error_string(ctx, "%s", j->out.error_string);
724 werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
725 if (!W_ERROR_IS_OK(werr)) {
735 WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
736 struct NetProvisionComputerAccount *r)
739 enum ndr_err_code ndr_err;
740 const char *b64_bin_data_str;
742 struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
743 struct ODJ_PROVISION_DATA *p;
744 TALLOC_CTX *mem_ctx = talloc_new(ctx);
746 if (r->in.provision_bin_data == NULL &&
747 r->in.provision_text_data == NULL) {
748 return WERR_INVALID_PARAMETER;
750 if (r->in.provision_bin_data != NULL &&
751 r->in.provision_text_data != NULL) {
752 return WERR_INVALID_PARAMETER;
754 if (r->in.provision_bin_data == NULL &&
755 r->in.provision_bin_data_size != NULL) {
756 return WERR_INVALID_PARAMETER;
758 if (r->in.provision_bin_data != NULL &&
759 r->in.provision_bin_data_size == NULL) {
760 return WERR_INVALID_PARAMETER;
763 if (r->in.domain == NULL) {
764 return WERR_INVALID_PARAMETER;
767 if (r->in.machine_name == NULL) {
768 return WERR_INVALID_PARAMETER;
771 werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
772 if (!W_ERROR_IS_OK(werr)) {
773 talloc_free(mem_ctx);
777 ZERO_STRUCT(odj_provision_data);
779 odj_provision_data.s.p = p;
781 ndr_err = ndr_push_struct_blob(&blob, ctx, &odj_provision_data,
782 (ndr_push_flags_fn_t)ndr_push_ODJ_PROVISION_DATA_serialized_ptr);
783 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
784 talloc_free(mem_ctx);
785 return W_ERROR(NERR_BadOfflineJoinInfo);
788 talloc_free(mem_ctx);
790 if (r->out.provision_text_data != NULL) {
791 b64_bin_data_str = base64_encode_data_blob(ctx, blob);
792 if (b64_bin_data_str == NULL) {
793 return WERR_NOT_ENOUGH_MEMORY;
795 *r->out.provision_text_data = b64_bin_data_str;
798 if (r->out.provision_bin_data != NULL &&
799 r->out.provision_bin_data_size != NULL) {
800 *r->out.provision_bin_data = blob.data;
801 *r->out.provision_bin_data_size = blob.length;
807 /****************************************************************
808 ****************************************************************/
810 WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
811 struct NetRequestOfflineDomainJoin *r)
813 return WERR_NOT_SUPPORTED;
816 /****************************************************************
817 ****************************************************************/
819 static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
820 const struct ODJ_WIN7BLOB *win7blob,
821 const struct ODJ_PROVISION_DATA *odj_provision_data)
823 struct libnet_JoinCtx *j = NULL;
826 werr = libnet_init_JoinCtx(ctx, &j);
827 if (!W_ERROR_IS_OK(werr)) {
831 j->in.domain_name = talloc_strdup(j, win7blob->lpDomain);
832 if (j->in.domain_name == NULL) {
834 return WERR_NOT_ENOUGH_MEMORY;
837 talloc_free(discard_const_p(char *, j->in.machine_name));
838 j->in.machine_name = talloc_strdup(j, win7blob->lpMachineName);
839 if (j->in.machine_name == NULL) {
841 return WERR_NOT_ENOUGH_MEMORY;
844 j->in.machine_password = talloc_strdup(j, win7blob->lpMachinePassword);
845 if (j->in.machine_password == NULL) {
847 return WERR_NOT_ENOUGH_MEMORY;
850 j->in.request_offline_join = true;
851 j->in.odj_provision_data = discard_const(odj_provision_data);
853 j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
854 WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
856 werr = libnet_Join(j, j);
857 if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
858 libnetapi_set_error_string(ctx, "%s", j->out.error_string);
868 WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
869 struct NetRequestOfflineDomainJoin *r)
871 DATA_BLOB blob, blob_base64;
872 enum ndr_err_code ndr_err;
873 struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
875 struct ODJ_WIN7BLOB win7blob = { 0 };
878 if (r->in.provision_bin_data == NULL ||
879 r->in.provision_bin_data_size == 0) {
880 return W_ERROR(NERR_NoOfflineJoinInfo);
883 if (r->in.provision_bin_data_size < 2) {
884 return W_ERROR(NERR_BadOfflineJoinInfo);
887 if (r->in.provision_bin_data[0] == 0xff &&
888 r->in.provision_bin_data[1] == 0xfe) {
889 ok = convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX,
890 r->in.provision_bin_data+2,
891 r->in.provision_bin_data_size-2,
893 &blob_base64.length);
895 return W_ERROR(NERR_BadOfflineJoinInfo);
898 blob_base64 = data_blob(r->in.provision_bin_data,
899 r->in.provision_bin_data_size);
902 blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
904 ndr_err = ndr_pull_struct_blob(&blob, ctx, &odj_provision_data,
905 (ndr_pull_flags_fn_t)ndr_pull_ODJ_PROVISION_DATA_serialized_ptr);
906 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
907 return W_ERROR(NERR_BadOfflineJoinInfo);
910 if (DEBUGLEVEL >= 10) {
911 NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
914 if (odj_provision_data.s.p->ulVersion != 1) {
915 return W_ERROR(NERR_ProvisioningBlobUnsupported);
918 werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
919 if (!W_ERROR_IS_OK(werr)) {
923 if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
924 return WERR_NERR_SETUPNOTJOINED;
927 werr = NetRequestOfflineDomainJoin_backend(ctx,
929 odj_provision_data.s.p);
930 if (!W_ERROR_IS_OK(werr)) {
934 return W_ERROR(NERR_JoinPerformedMustRestart);