s3:libads: Allocate ads->auth.password under ADS_STRUCT talloc context
[samba.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         SAFE_FREE(ads->auth.user_name);
438         if (r->in.account) {
439                 ads->auth.user_name = SMB_STRDUP(r->in.account);
440         } else {
441                 const char *username = NULL;
442
443                 libnetapi_get_username(ctx, &username);
444                 if (username != NULL) {
445                         ads->auth.user_name = SMB_STRDUP(username);
446                 }
447         }
448
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;
454                         goto out;
455                 }
456         } else {
457                 const char *password = NULL;
458
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;
464                                 goto out;
465                         }
466                 }
467         }
468
469         ads_status = ads_connect_user_creds(ads);
470         if (!ADS_ERR_OK(ads_status)) {
471                 ret = WERR_NERR_DEFAULTJOINREQUIRED;
472                 goto out;
473         }
474
475         ads_status = ads_get_joinable_ous(ads, ctx, &p, &s);
476         if (!ADS_ERR_OK(ads_status)) {
477                 ret = WERR_NERR_DEFAULTJOINREQUIRED;
478                 goto out;
479         }
480         *r->out.ous = discard_const_p(const char *, p);
481         *r->out.ou_count = s;
482
483         ret = WERR_OK;
484 out:
485         TALLOC_FREE(tmp_ctx);
486
487         return ret;
488 #else
489         return WERR_NOT_SUPPORTED;
490 #endif
491 }
492
493 /****************************************************************
494 ****************************************************************/
495
496 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
497                            struct NetGetJoinableOUs *r)
498 {
499         struct rpc_pipe_client *pipe_cli = NULL;
500         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
501         NTSTATUS status;
502         WERROR werr;
503         struct dcerpc_binding_handle *b;
504         DATA_BLOB session_key;
505
506         werr = libnetapi_open_pipe(ctx, r->in.server_name,
507                                    &ndr_table_wkssvc,
508                                    &pipe_cli);
509         if (!W_ERROR_IS_OK(werr)) {
510                 goto done;
511         }
512
513         b = pipe_cli->binding_handle;
514
515         if (r->in.password) {
516
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);
520                         goto done;
521                 }
522
523                 werr = encode_wkssvc_join_password_buffer(ctx,
524                                                           r->in.password,
525                                                           &session_key,
526                                                           &encrypted_password);
527                 if (!W_ERROR_IS_OK(werr)) {
528                         goto done;
529                 }
530         }
531
532         status = dcerpc_wkssvc_NetrGetJoinableOus2(b, talloc_tos(),
533                                                    r->in.server_name,
534                                                    r->in.domain,
535                                                    r->in.account,
536                                                    encrypted_password,
537                                                    r->out.ou_count,
538                                                    r->out.ous,
539                                                    &werr);
540         if (!NT_STATUS_IS_OK(status)) {
541                 werr = ntstatus_to_werror(status);
542                 goto done;
543         }
544
545  done:
546         return werr;
547 }
548
549 /****************************************************************
550 ****************************************************************/
551
552 WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
553                                   struct NetRenameMachineInDomain *r)
554 {
555         struct rpc_pipe_client *pipe_cli = NULL;
556         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
557         NTSTATUS status;
558         WERROR werr;
559         struct dcerpc_binding_handle *b;
560         DATA_BLOB session_key;
561
562         werr = libnetapi_open_pipe(ctx, r->in.server_name,
563                                    &ndr_table_wkssvc,
564                                    &pipe_cli);
565         if (!W_ERROR_IS_OK(werr)) {
566                 goto done;
567         }
568
569         b = pipe_cli->binding_handle;
570
571         if (r->in.password) {
572
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);
576                         goto done;
577                 }
578
579                 werr = encode_wkssvc_join_password_buffer(ctx,
580                                                           r->in.password,
581                                                           &session_key,
582                                                           &encrypted_password);
583                 if (!W_ERROR_IS_OK(werr)) {
584                         goto done;
585                 }
586         }
587
588         status = dcerpc_wkssvc_NetrRenameMachineInDomain2(b, talloc_tos(),
589                                                           r->in.server_name,
590                                                           r->in.new_machine_name,
591                                                           r->in.account,
592                                                           encrypted_password,
593                                                           r->in.rename_options,
594                                                           &werr);
595         if (!NT_STATUS_IS_OK(status)) {
596                 werr = ntstatus_to_werror(status);
597                 goto done;
598         }
599
600  done:
601         return werr;
602 }
603
604 /****************************************************************
605 ****************************************************************/
606
607 WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
608                                   struct NetRenameMachineInDomain *r)
609 {
610         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
611 }
612
613 /****************************************************************
614 ****************************************************************/
615
616 WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
617                                      struct NetProvisionComputerAccount *r)
618 {
619         return NetProvisionComputerAccount_l(ctx, r);
620 }
621
622 /****************************************************************
623 ****************************************************************/
624
625 static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
626                                                   struct NetProvisionComputerAccount *r,
627                                                   TALLOC_CTX *mem_ctx,
628                                                   struct ODJ_PROVISION_DATA **p)
629 {
630         WERROR werr;
631         struct libnet_JoinCtx *j = NULL;
632         int use_kerberos = 0;
633         const char *username = NULL;
634
635         werr = libnet_init_JoinCtx(mem_ctx, &j);
636         if (!W_ERROR_IS_OK(werr)) {
637                 return werr;
638         }
639
640         j->in.domain_name = talloc_strdup(j, r->in.domain);
641         if (j->in.domain_name == NULL) {
642                 talloc_free(j);
643                 return WERR_NOT_ENOUGH_MEMORY;
644         }
645
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) {
649                 talloc_free(j);
650                 return WERR_NOT_ENOUGH_MEMORY;
651         }
652
653         if (r->in.dcname) {
654                 j->in.dc_name = talloc_strdup(j, r->in.dcname);
655                 if (j->in.dc_name == NULL) {
656                         talloc_free(j);
657                         return WERR_NOT_ENOUGH_MEMORY;
658                 }
659         }
660
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) {
664                         talloc_free(j);
665                         return WERR_NOT_ENOUGH_MEMORY;
666                 }
667         }
668
669         libnetapi_get_username(ctx, &username);
670         if (username == NULL) {
671                 talloc_free(j);
672                 return WERR_NERR_BADUSERNAME;
673         }
674
675         j->in.admin_account = talloc_strdup(j, username);
676         if (j->in.admin_account == NULL) {
677                 talloc_free(j);
678                 return WERR_NOT_ENOUGH_MEMORY;
679         }
680
681         libnetapi_get_use_kerberos(ctx, &use_kerberos);
682         if (!use_kerberos) {
683                 const char *password = NULL;
684
685                 libnetapi_get_password(ctx, &password);
686                 if (password == NULL) {
687                         talloc_free(j);
688                         return WERR_NERR_BADPASSWORD;
689                 }
690                 j->in.admin_password = talloc_strdup(j, password);
691                 if (j->in.admin_password == NULL) {
692                         talloc_free(j);
693                         return WERR_NOT_ENOUGH_MEMORY;
694                 }
695         }
696
697         j->in.use_kerberos = use_kerberos;
698         j->in.debug = true;
699         j->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
700                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
701
702         if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
703                 j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
704         }
705
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) {
710                         talloc_free(j);
711                         return WERR_NOT_ENOUGH_MEMORY;
712                 }
713         }
714
715         j->in.provision_computer_account_only = true;
716
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);
720                 talloc_free(j);
721                 return werr;
722         }
723
724         werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
725         if (!W_ERROR_IS_OK(werr)) {
726                 talloc_free(j);
727                 return werr;
728         }
729
730         TALLOC_FREE(j);
731
732         return WERR_OK;
733 }
734
735 WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
736                                      struct NetProvisionComputerAccount *r)
737 {
738         WERROR werr;
739         enum ndr_err_code ndr_err;
740         const char *b64_bin_data_str;
741         DATA_BLOB blob;
742         struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
743         struct ODJ_PROVISION_DATA *p;
744         TALLOC_CTX *mem_ctx = talloc_new(ctx);
745
746         if (r->in.provision_bin_data == NULL &&
747             r->in.provision_text_data == NULL) {
748                 return WERR_INVALID_PARAMETER;
749         }
750         if (r->in.provision_bin_data != NULL &&
751             r->in.provision_text_data != NULL) {
752                 return WERR_INVALID_PARAMETER;
753         }
754         if (r->in.provision_bin_data == NULL &&
755             r->in.provision_bin_data_size != NULL) {
756                 return WERR_INVALID_PARAMETER;
757         }
758         if (r->in.provision_bin_data != NULL &&
759            r->in.provision_bin_data_size == NULL) {
760                 return WERR_INVALID_PARAMETER;
761         }
762
763         if (r->in.domain == NULL) {
764                 return WERR_INVALID_PARAMETER;
765         }
766
767         if (r->in.machine_name == NULL) {
768                 return WERR_INVALID_PARAMETER;
769         }
770
771         werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
772         if (!W_ERROR_IS_OK(werr)) {
773                 talloc_free(mem_ctx);
774                 return werr;
775         }
776
777         ZERO_STRUCT(odj_provision_data);
778
779         odj_provision_data.s.p = p;
780
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);
786         }
787
788         talloc_free(mem_ctx);
789
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;
794                 }
795                 *r->out.provision_text_data = b64_bin_data_str;
796         }
797
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;
802         }
803
804         return werr;
805 }
806
807 /****************************************************************
808 ****************************************************************/
809
810 WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
811                                      struct NetRequestOfflineDomainJoin *r)
812 {
813         return WERR_NOT_SUPPORTED;
814 }
815
816 /****************************************************************
817 ****************************************************************/
818
819 static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
820                                                   const struct ODJ_WIN7BLOB *win7blob,
821                                                   const struct ODJ_PROVISION_DATA *odj_provision_data)
822 {
823         struct libnet_JoinCtx *j = NULL;
824         WERROR werr;
825
826         werr = libnet_init_JoinCtx(ctx, &j);
827         if (!W_ERROR_IS_OK(werr)) {
828                 return werr;
829         }
830
831         j->in.domain_name = talloc_strdup(j, win7blob->lpDomain);
832         if (j->in.domain_name == NULL) {
833                 talloc_free(j);
834                 return WERR_NOT_ENOUGH_MEMORY;
835         }
836
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) {
840                 talloc_free(j);
841                 return WERR_NOT_ENOUGH_MEMORY;
842         }
843
844         j->in.machine_password = talloc_strdup(j, win7blob->lpMachinePassword);
845         if (j->in.machine_password == NULL) {
846                 talloc_free(j);
847                 return WERR_NOT_ENOUGH_MEMORY;
848         }
849
850         j->in.request_offline_join = true;
851         j->in.odj_provision_data = discard_const(odj_provision_data);
852         j->in.debug = true;
853         j->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
854                                   WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
855
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);
859                 talloc_free(j);
860                 return werr;
861         }
862
863         TALLOC_FREE(j);
864
865         return WERR_OK;
866 }
867
868 WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
869                                      struct NetRequestOfflineDomainJoin *r)
870 {
871         DATA_BLOB blob, blob_base64;
872         enum ndr_err_code ndr_err;
873         struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
874         bool ok;
875         struct ODJ_WIN7BLOB win7blob = { 0 };
876         WERROR werr;
877
878         if (r->in.provision_bin_data == NULL ||
879             r->in.provision_bin_data_size == 0) {
880                 return W_ERROR(NERR_NoOfflineJoinInfo);
881         }
882
883         if (r->in.provision_bin_data_size < 2) {
884                 return W_ERROR(NERR_BadOfflineJoinInfo);
885         }
886
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,
892                                            &blob_base64.data,
893                                            &blob_base64.length);
894                 if (!ok) {
895                         return W_ERROR(NERR_BadOfflineJoinInfo);
896                 }
897         } else {
898                 blob_base64 = data_blob(r->in.provision_bin_data,
899                                         r->in.provision_bin_data_size);
900         }
901
902         blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
903
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);
908         }
909
910         if (DEBUGLEVEL >= 10) {
911                 NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
912         }
913
914         if (odj_provision_data.s.p->ulVersion != 1) {
915                 return W_ERROR(NERR_ProvisioningBlobUnsupported);
916         }
917
918         werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
919         if (!W_ERROR_IS_OK(werr)) {
920                 return werr;
921         }
922
923         if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
924                 return WERR_NERR_SETUPNOTJOINED;
925         }
926
927         werr = NetRequestOfflineDomainJoin_backend(ctx,
928                                                    &win7blob,
929                                                    odj_provision_data.s.p);
930         if (!W_ERROR_IS_OK(werr)) {
931                 return werr;
932         }
933
934         return W_ERROR(NERR_JoinPerformedMustRestart);
935 }