s3:libnetapi: Return error from RequestOfflineJoin
[janger/samba-autobuild-v4-18-test/.git] / source3 / lib / netapi / joindomain.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Join Support
4  *  Copyright (C) Guenther Deschner 2007-2008
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
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"
36
37 /****************************************************************
38 ****************************************************************/
39
40 WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
41                        struct NetJoinDomain *r)
42 {
43         struct libnet_JoinCtx *j = NULL;
44         struct libnetapi_private_ctx *priv;
45         WERROR werr;
46
47         priv = talloc_get_type_abort(mem_ctx->private_data,
48                 struct libnetapi_private_ctx);
49
50         if (!r->in.domain) {
51                 return WERR_INVALID_PARAMETER;
52         }
53
54         werr = libnet_init_JoinCtx(mem_ctx, &j);
55         W_ERROR_NOT_OK_RETURN(werr);
56
57         j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
58         W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
59
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);
73                 }
74
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);
78         }
79
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);
83         }
84
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);
88         }
89
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);
93         }
94
95         j->in.join_flags = r->in.join_flags;
96         j->in.modify_config = true;
97         j->in.debug = true;
98
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);
102         }
103         TALLOC_FREE(j);
104
105         return werr;
106 }
107
108 /****************************************************************
109 ****************************************************************/
110
111 WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
112                        struct NetJoinDomain *r)
113 {
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;
121
122         if (IS_DC) {
123                 return WERR_NERR_SETUPDOMAINCONTROLLER;
124         }
125
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;
131         }
132
133         b = pipe_cli->binding_handle;
134
135         if (r->in.password) {
136
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;
141                 }
142
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;
149                 }
150         }
151
152         old_timeout = rpccli_set_timeout(pipe_cli, 600000);
153
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;
165         }
166
167  done:
168         if (pipe_cli && old_timeout) {
169                 rpccli_set_timeout(pipe_cli, old_timeout);
170         }
171
172         return werr;
173 }
174 /****************************************************************
175 ****************************************************************/
176
177 WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
178                          struct NetUnjoinDomain *r)
179 {
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();
186
187         priv = talloc_get_type_abort(mem_ctx->private_data,
188                 struct libnetapi_private_ctx);
189
190         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
191                 return WERR_NERR_SETUPNOTJOINED;
192         }
193
194         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
195         W_ERROR_NOT_OK_RETURN(werr);
196
197         if (realm[0] != '\0') {
198                 domain = realm;
199         } else {
200                 domain = lp_workgroup();
201         }
202
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);
221                 }
222
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);
226
227                 u->in.domain_name = domain;
228         }
229
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);
233         }
234
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);
238         }
239
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;
245
246         u->in.domain_sid = &domain_sid;
247
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);
251         }
252         TALLOC_FREE(u);
253
254         return werr;
255 }
256
257 /****************************************************************
258 ****************************************************************/
259
260 WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
261                          struct NetUnjoinDomain *r)
262 {
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;
270
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;
276         }
277
278         b = pipe_cli->binding_handle;
279
280         if (r->in.password) {
281
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;
286                 }
287
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;
294                 }
295         }
296
297         old_timeout = rpccli_set_timeout(pipe_cli, 60000);
298
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;
308         }
309
310  done:
311         if (pipe_cli && old_timeout) {
312                 rpccli_set_timeout(pipe_cli, old_timeout);
313         }
314
315         return werr;
316 }
317
318 /****************************************************************
319 ****************************************************************/
320
321 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
322                                struct NetGetJoinInformation *r)
323 {
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;
329
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;
335         }
336
337         b = pipe_cli->binding_handle;
338
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;
347         }
348
349         if (!W_ERROR_IS_OK(werr)) {
350                 goto done;
351         }
352
353         *r->out.name_buffer = talloc_strdup(ctx, buffer);
354         W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
355
356  done:
357         return werr;
358 }
359
360 /****************************************************************
361 ****************************************************************/
362
363 WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
364                                struct NetGetJoinInformation *r)
365 {
366         const char *realm = lp_realm();
367
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());
372         }
373         if (!*r->out.name_buffer) {
374                 return WERR_NOT_ENOUGH_MEMORY;
375         }
376
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;
388         }
389
390         return WERR_OK;
391 }
392
393 /****************************************************************
394 ****************************************************************/
395
396 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
397                            struct NetGetJoinableOUs *r)
398 {
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;
412
413         priv = talloc_get_type_abort(ctx->private_data,
414                 struct libnetapi_private_ctx);
415
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;
423         }
424
425         dc = strip_hostname(info->dc_unc);
426
427         ads = ads_init(tmp_ctx,
428                        info->domain_name,
429                        info->domain_name,
430                        dc,
431                        ADS_SASL_PLAIN);
432         if (!ads) {
433                 ret = WERR_GEN_FAILURE;
434                 goto out;
435         }
436
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;
443                 }
444         } else {
445                 const char *username = NULL;
446
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;
453                         }
454                 }
455         }
456
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;
463                 }
464         } else {
465                 const char *password = NULL;
466
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;
473                         }
474                 }
475         }
476
477         ads_status = ads_connect_user_creds(ads);
478         if (!ADS_ERR_OK(ads_status)) {
479                 ret = WERR_NERR_DEFAULTJOINREQUIRED;
480                 goto out;
481         }
482
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;
487         }
488         *r->out.ous = discard_const_p(const char *, p);
489         *r->out.ou_count = s;
490
491         ret = WERR_OK;
492 out:
493         TALLOC_FREE(tmp_ctx);
494
495         return ret;
496 #else
497         return WERR_NOT_SUPPORTED;
498 #endif
499 }
500
501 /****************************************************************
502 ****************************************************************/
503
504 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
505                            struct NetGetJoinableOUs *r)
506 {
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;
513
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;
519         }
520
521         b = pipe_cli->binding_handle;
522
523         if (r->in.password) {
524
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;
529                 }
530
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;
537                 }
538         }
539
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;
551         }
552
553  done:
554         return werr;
555 }
556
557 /****************************************************************
558 ****************************************************************/
559
560 WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
561                                   struct NetRenameMachineInDomain *r)
562 {
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;
569
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;
575         }
576
577         b = pipe_cli->binding_handle;
578
579         if (r->in.password) {
580
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;
585                 }
586
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;
593                 }
594         }
595
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;
606         }
607
608  done:
609         return werr;
610 }
611
612 /****************************************************************
613 ****************************************************************/
614
615 WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
616                                   struct NetRenameMachineInDomain *r)
617 {
618         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
619 }
620
621 /****************************************************************
622 ****************************************************************/
623
624 WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
625                                      struct NetProvisionComputerAccount *r)
626 {
627         return NetProvisionComputerAccount_l(ctx, r);
628 }
629
630 /****************************************************************
631 ****************************************************************/
632
633 static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
634                                                   struct NetProvisionComputerAccount *r,
635                                                   TALLOC_CTX *mem_ctx,
636                                                   struct ODJ_PROVISION_DATA **p)
637 {
638         WERROR werr;
639         struct libnet_JoinCtx *j = NULL;
640         int use_kerberos = 0;
641         const char *username = NULL;
642
643         werr = libnet_init_JoinCtx(mem_ctx, &j);
644         if (!W_ERROR_IS_OK(werr)) {
645                 return werr;
646         }
647
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;
652         }
653
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;
659         }
660
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;
666                 }
667         }
668
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;
674                 }
675         }
676
677         libnetapi_get_username(ctx, &username);
678         if (username == NULL) {
679                 talloc_free(j);
680                 return WERR_NERR_BADUSERNAME;
681         }
682
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;
687         }
688
689         libnetapi_get_use_kerberos(ctx, &use_kerberos);
690         if (!use_kerberos) {
691                 const char *password = NULL;
692
693                 libnetapi_get_password(ctx, &password);
694                 if (password == NULL) {
695                         talloc_free(j);
696                         return WERR_NERR_BADPASSWORD;
697                 }
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;
702                 }
703         }
704
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;
709
710         if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
711                 j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
712         }
713
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;
720                 }
721         }
722
723         j->in.provision_computer_account_only = true;
724
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;
730         }
731
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;
736         }
737
738         TALLOC_FREE(j);
739
740         return WERR_OK;
741 }
742
743 WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
744                                      struct NetProvisionComputerAccount *r)
745 {
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);
753
754         if (r->in.provision_bin_data == NULL &&
755             r->in.provision_text_data == NULL) {
756                 return WERR_INVALID_PARAMETER;
757         }
758         if (r->in.provision_bin_data != NULL &&
759             r->in.provision_text_data != NULL) {
760                 return WERR_INVALID_PARAMETER;
761         }
762         if (r->in.provision_bin_data == NULL &&
763             r->in.provision_bin_data_size != NULL) {
764                 return WERR_INVALID_PARAMETER;
765         }
766         if (r->in.provision_bin_data != NULL &&
767            r->in.provision_bin_data_size == NULL) {
768                 return WERR_INVALID_PARAMETER;
769         }
770
771         if (r->in.domain == NULL) {
772                 return WERR_INVALID_PARAMETER;
773         }
774
775         if (r->in.machine_name == NULL) {
776                 return WERR_INVALID_PARAMETER;
777         }
778
779         werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
780         if (!W_ERROR_IS_OK(werr)) {
781                 talloc_free(mem_ctx);
782                 return werr;
783         }
784
785         ZERO_STRUCT(odj_provision_data);
786
787         odj_provision_data.s.p = p;
788
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);
794         }
795
796         talloc_free(mem_ctx);
797
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;
802                 }
803                 *r->out.provision_text_data = b64_bin_data_str;
804         }
805
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;
810         }
811
812         return werr;
813 }
814
815 /****************************************************************
816 ****************************************************************/
817
818 WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
819                                      struct NetRequestOfflineDomainJoin *r)
820 {
821         return WERR_NOT_SUPPORTED;
822 }
823
824 /****************************************************************
825 ****************************************************************/
826
827 static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
828                                                   const struct ODJ_WIN7BLOB *win7blob,
829                                                   const struct ODJ_PROVISION_DATA *odj_provision_data)
830 {
831         struct libnet_JoinCtx *j = NULL;
832         WERROR werr;
833
834         werr = libnet_init_JoinCtx(ctx, &j);
835         if (!W_ERROR_IS_OK(werr)) {
836                 return werr;
837         }
838
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;
843         }
844
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;
850         }
851
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;
856         }
857
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;
863
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);
868                 }
869                 talloc_free(j);
870                 return werr;
871         }
872
873         TALLOC_FREE(j);
874
875         return WERR_OK;
876 }
877
878 WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
879                                      struct NetRequestOfflineDomainJoin *r)
880 {
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;
887
888         if (r->in.provision_bin_data == NULL ||
889             r->in.provision_bin_data_size == 0) {
890                 return W_ERROR(NERR_NoOfflineJoinInfo);
891         }
892
893         if (r->in.provision_bin_data_size < 2) {
894                 return W_ERROR(NERR_BadOfflineJoinInfo);
895         }
896
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);
906                 }
907         } else {
908                 blob_base64 = data_blob(r->in.provision_bin_data,
909                                         r->in.provision_bin_data_size);
910         }
911
912         blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
913
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);
918         }
919
920         if (DEBUGLEVEL >= 10) {
921                 NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
922         }
923
924         if (odj_provision_data.s.p->ulVersion != 1) {
925                 return W_ERROR(NERR_ProvisioningBlobUnsupported);
926         }
927
928         werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
929         if (!W_ERROR_IS_OK(werr)) {
930                 return werr;
931         }
932
933         if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
934                 return WERR_NERR_SETUPNOTJOINED;
935         }
936
937         werr = NetRequestOfflineDomainJoin_backend(ctx,
938                                                    &win7blob,
939                                                    odj_provision_data.s.p);
940         if (!W_ERROR_IS_OK(werr)) {
941                 return werr;
942         }
943
944         return W_ERROR(NERR_JoinPerformedMustRestart);
945 }