s3-rpc_client: Move client pipe functions to own header.
[samba.git] / source3 / libnet / libnet_join.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet Join Support
4  *  Copyright (C) Gerald (Jerry) Carter 2006
5  *  Copyright (C) Guenther Deschner 2007-2008
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "ads.h"
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
35 #include "secrets.h"
36 #include "rpc_client/init_lsa.h"
37 #include "rpc_client/cli_pipe.h"
38 #include "krb5_env.h"
39 #include "../libcli/security/security.h"
40
41 /****************************************************************
42 ****************************************************************/
43
44 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
45         do { \
46                 char *str = NULL; \
47                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
48                 DEBUG(1,("libnet_Join:\n%s", str)); \
49                 TALLOC_FREE(str); \
50         } while (0)
51
52 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
53         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
54 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
55         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
56
57 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
58         do { \
59                 char *str = NULL; \
60                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
61                 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
62                 TALLOC_FREE(str); \
63         } while (0)
64
65 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
66         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
67 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
68         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
69
70 /****************************************************************
71 ****************************************************************/
72
73 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
74                                          struct libnet_JoinCtx *r,
75                                          const char *format, ...)
76 {
77         va_list args;
78
79         if (r->out.error_string) {
80                 return;
81         }
82
83         va_start(args, format);
84         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
85         va_end(args);
86 }
87
88 /****************************************************************
89 ****************************************************************/
90
91 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
92                                            struct libnet_UnjoinCtx *r,
93                                            const char *format, ...)
94 {
95         va_list args;
96
97         if (r->out.error_string) {
98                 return;
99         }
100
101         va_start(args, format);
102         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
103         va_end(args);
104 }
105
106 #ifdef HAVE_ADS
107
108 /****************************************************************
109 ****************************************************************/
110
111 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
112                                      const char *netbios_domain_name,
113                                      const char *dc_name,
114                                      const char *user_name,
115                                      const char *password,
116                                      ADS_STRUCT **ads)
117 {
118         ADS_STATUS status;
119         ADS_STRUCT *my_ads = NULL;
120         char *cp;
121
122         my_ads = ads_init(dns_domain_name,
123                           netbios_domain_name,
124                           dc_name);
125         if (!my_ads) {
126                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
127         }
128
129         if (user_name) {
130                 SAFE_FREE(my_ads->auth.user_name);
131                 my_ads->auth.user_name = SMB_STRDUP(user_name);
132                 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
133                         *cp++ = '\0';
134                         SAFE_FREE(my_ads->auth.realm);
135                         my_ads->auth.realm = smb_xstrdup(cp);
136                         strupper_m(my_ads->auth.realm);
137                 }
138         }
139
140         if (password) {
141                 SAFE_FREE(my_ads->auth.password);
142                 my_ads->auth.password = SMB_STRDUP(password);
143         }
144
145         status = ads_connect_user_creds(my_ads);
146         if (!ADS_ERR_OK(status)) {
147                 ads_destroy(&my_ads);
148                 return status;
149         }
150
151         *ads = my_ads;
152         return ADS_SUCCESS;
153 }
154
155 /****************************************************************
156 ****************************************************************/
157
158 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
159                                           struct libnet_JoinCtx *r)
160 {
161         ADS_STATUS status;
162
163         status = libnet_connect_ads(r->out.dns_domain_name,
164                                     r->out.netbios_domain_name,
165                                     r->in.dc_name,
166                                     r->in.admin_account,
167                                     r->in.admin_password,
168                                     &r->in.ads);
169         if (!ADS_ERR_OK(status)) {
170                 libnet_join_set_error_string(mem_ctx, r,
171                         "failed to connect to AD: %s",
172                         ads_errstr(status));
173                 return status;
174         }
175
176         if (!r->out.netbios_domain_name) {
177                 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
178                                                            r->in.ads->server.workgroup);
179                 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
180         }
181
182         if (!r->out.dns_domain_name) {
183                 r->out.dns_domain_name = talloc_strdup(mem_ctx,
184                                                        r->in.ads->config.realm);
185                 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
186         }
187
188         r->out.domain_is_ad = true;
189
190         return ADS_SUCCESS;
191 }
192
193 /****************************************************************
194 ****************************************************************/
195
196 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
197                                             struct libnet_UnjoinCtx *r)
198 {
199         ADS_STATUS status;
200
201         status = libnet_connect_ads(r->in.domain_name,
202                                     r->in.domain_name,
203                                     r->in.dc_name,
204                                     r->in.admin_account,
205                                     r->in.admin_password,
206                                     &r->in.ads);
207         if (!ADS_ERR_OK(status)) {
208                 libnet_unjoin_set_error_string(mem_ctx, r,
209                         "failed to connect to AD: %s",
210                         ads_errstr(status));
211         }
212
213         return status;
214 }
215
216 /****************************************************************
217  join a domain using ADS (LDAP mods)
218 ****************************************************************/
219
220 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
221                                                      struct libnet_JoinCtx *r)
222 {
223         ADS_STATUS status;
224         LDAPMessage *res = NULL;
225         const char *attrs[] = { "dn", NULL };
226         bool moved = false;
227
228         status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
229         if (!ADS_ERR_OK(status)) {
230                 return status;
231         }
232
233         status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
234         if (!ADS_ERR_OK(status)) {
235                 return status;
236         }
237
238         if (ads_count_replies(r->in.ads, res) != 1) {
239                 ads_msgfree(r->in.ads, res);
240                 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
241         }
242
243         ads_msgfree(r->in.ads, res);
244
245         /* Attempt to create the machine account and bail if this fails.
246            Assume that the admin wants exactly what they requested */
247
248         status = ads_create_machine_acct(r->in.ads,
249                                          r->in.machine_name,
250                                          r->in.account_ou);
251
252         if (ADS_ERR_OK(status)) {
253                 DEBUG(1,("machine account creation created\n"));
254                 return status;
255         } else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
256                     (status.err.rc == LDAP_ALREADY_EXISTS)) {
257                 status = ADS_SUCCESS;
258         }
259
260         if (!ADS_ERR_OK(status)) {
261                 DEBUG(1,("machine account creation failed\n"));
262                 return status;
263         }
264
265         status = ads_move_machine_acct(r->in.ads,
266                                        r->in.machine_name,
267                                        r->in.account_ou,
268                                        &moved);
269         if (!ADS_ERR_OK(status)) {
270                 DEBUG(1,("failure to locate/move pre-existing "
271                         "machine account\n"));
272                 return status;
273         }
274
275         DEBUG(1,("The machine account %s the specified OU.\n",
276                 moved ? "was moved into" : "already exists in"));
277
278         return status;
279 }
280
281 /****************************************************************
282 ****************************************************************/
283
284 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
285                                                     struct libnet_UnjoinCtx *r)
286 {
287         ADS_STATUS status;
288
289         if (!r->in.ads) {
290                 status = libnet_unjoin_connect_ads(mem_ctx, r);
291                 if (!ADS_ERR_OK(status)) {
292                         libnet_unjoin_set_error_string(mem_ctx, r,
293                                 "failed to connect to AD: %s",
294                                 ads_errstr(status));
295                         return status;
296                 }
297         }
298
299         status = ads_leave_realm(r->in.ads, r->in.machine_name);
300         if (!ADS_ERR_OK(status)) {
301                 libnet_unjoin_set_error_string(mem_ctx, r,
302                         "failed to leave realm: %s",
303                         ads_errstr(status));
304                 return status;
305         }
306
307         return ADS_SUCCESS;
308 }
309
310 /****************************************************************
311 ****************************************************************/
312
313 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
314                                                 struct libnet_JoinCtx *r)
315 {
316         ADS_STATUS status;
317         LDAPMessage *res = NULL;
318         char *dn = NULL;
319
320         if (!r->in.machine_name) {
321                 return ADS_ERROR(LDAP_NO_MEMORY);
322         }
323
324         status = ads_find_machine_acct(r->in.ads,
325                                        &res,
326                                        r->in.machine_name);
327         if (!ADS_ERR_OK(status)) {
328                 return status;
329         }
330
331         if (ads_count_replies(r->in.ads, res) != 1) {
332                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
333                 goto done;
334         }
335
336         dn = ads_get_dn(r->in.ads, mem_ctx, res);
337         if (!dn) {
338                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
339                 goto done;
340         }
341
342         r->out.dn = talloc_strdup(mem_ctx, dn);
343         if (!r->out.dn) {
344                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
345                 goto done;
346         }
347
348  done:
349         ads_msgfree(r->in.ads, res);
350         TALLOC_FREE(dn);
351
352         return status;
353 }
354
355 /****************************************************************
356  Set a machines dNSHostName and servicePrincipalName attributes
357 ****************************************************************/
358
359 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
360                                               struct libnet_JoinCtx *r)
361 {
362         ADS_STATUS status;
363         ADS_MODLIST mods;
364         fstring my_fqdn;
365         const char *spn_array[3] = {NULL, NULL, NULL};
366         char *spn = NULL;
367
368         /* Find our DN */
369
370         status = libnet_join_find_machine_acct(mem_ctx, r);
371         if (!ADS_ERR_OK(status)) {
372                 return status;
373         }
374
375         /* Windows only creates HOST/shortname & HOST/fqdn. */
376
377         spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
378         if (!spn) {
379                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
380         }
381         strupper_m(spn);
382         spn_array[0] = spn;
383
384         if (!name_to_fqdn(my_fqdn, r->in.machine_name)
385             || (strchr(my_fqdn, '.') == NULL)) {
386                 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
387                              r->out.dns_domain_name);
388         }
389
390         strlower_m(my_fqdn);
391
392         if (!strequal(my_fqdn, r->in.machine_name)) {
393                 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
394                 if (!spn) {
395                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
396                 }
397                 spn_array[1] = spn;
398         }
399
400         mods = ads_init_mods(mem_ctx);
401         if (!mods) {
402                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
403         }
404
405         /* fields of primary importance */
406
407         status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
408         if (!ADS_ERR_OK(status)) {
409                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
410         }
411
412         status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
413                                  spn_array);
414         if (!ADS_ERR_OK(status)) {
415                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
416         }
417
418         return ads_gen_mod(r->in.ads, r->out.dn, mods);
419 }
420
421 /****************************************************************
422 ****************************************************************/
423
424 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
425                                               struct libnet_JoinCtx *r)
426 {
427         ADS_STATUS status;
428         ADS_MODLIST mods;
429
430         if (!r->in.create_upn) {
431                 return ADS_SUCCESS;
432         }
433
434         /* Find our DN */
435
436         status = libnet_join_find_machine_acct(mem_ctx, r);
437         if (!ADS_ERR_OK(status)) {
438                 return status;
439         }
440
441         if (!r->in.upn) {
442                 r->in.upn = talloc_asprintf(mem_ctx,
443                                             "host/%s@%s",
444                                             r->in.machine_name,
445                                             r->out.dns_domain_name);
446                 if (!r->in.upn) {
447                         return ADS_ERROR(LDAP_NO_MEMORY);
448                 }
449         }
450
451         /* now do the mods */
452
453         mods = ads_init_mods(mem_ctx);
454         if (!mods) {
455                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
456         }
457
458         /* fields of primary importance */
459
460         status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
461         if (!ADS_ERR_OK(status)) {
462                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
463         }
464
465         return ads_gen_mod(r->in.ads, r->out.dn, mods);
466 }
467
468
469 /****************************************************************
470 ****************************************************************/
471
472 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
473                                                 struct libnet_JoinCtx *r)
474 {
475         ADS_STATUS status;
476         ADS_MODLIST mods;
477         char *os_sp = NULL;
478
479         if (!r->in.os_name || !r->in.os_version ) {
480                 return ADS_SUCCESS;
481         }
482
483         /* Find our DN */
484
485         status = libnet_join_find_machine_acct(mem_ctx, r);
486         if (!ADS_ERR_OK(status)) {
487                 return status;
488         }
489
490         /* now do the mods */
491
492         mods = ads_init_mods(mem_ctx);
493         if (!mods) {
494                 return ADS_ERROR(LDAP_NO_MEMORY);
495         }
496
497         os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
498         if (!os_sp) {
499                 return ADS_ERROR(LDAP_NO_MEMORY);
500         }
501
502         /* fields of primary importance */
503
504         status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
505                              r->in.os_name);
506         if (!ADS_ERR_OK(status)) {
507                 return status;
508         }
509
510         status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
511                              r->in.os_version);
512         if (!ADS_ERR_OK(status)) {
513                 return status;
514         }
515
516         status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
517                              os_sp);
518         if (!ADS_ERR_OK(status)) {
519                 return status;
520         }
521
522         return ads_gen_mod(r->in.ads, r->out.dn, mods);
523 }
524
525 /****************************************************************
526 ****************************************************************/
527
528 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
529                                       struct libnet_JoinCtx *r)
530 {
531         if (!USE_SYSTEM_KEYTAB) {
532                 return true;
533         }
534
535         if (ads_keytab_create_default(r->in.ads) != 0) {
536                 return false;
537         }
538
539         return true;
540 }
541
542 /****************************************************************
543 ****************************************************************/
544
545 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
546                                                  struct libnet_JoinCtx *r)
547 {
548         uint32_t domain_func;
549         ADS_STATUS status;
550         const char *salt = NULL;
551         char *std_salt = NULL;
552
553         status = ads_domain_func_level(r->in.ads, &domain_func);
554         if (!ADS_ERR_OK(status)) {
555                 libnet_join_set_error_string(mem_ctx, r,
556                         "failed to determine domain functional level: %s",
557                         ads_errstr(status));
558                 return false;
559         }
560
561         /* go ahead and setup the default salt */
562
563         std_salt = kerberos_standard_des_salt();
564         if (!std_salt) {
565                 libnet_join_set_error_string(mem_ctx, r,
566                         "failed to obtain standard DES salt");
567                 return false;
568         }
569
570         salt = talloc_strdup(mem_ctx, std_salt);
571         if (!salt) {
572                 return false;
573         }
574
575         SAFE_FREE(std_salt);
576
577         /* if it's a Windows functional domain, we have to look for the UPN */
578
579         if (domain_func == DS_DOMAIN_FUNCTION_2000) {
580                 char *upn;
581
582                 upn = ads_get_upn(r->in.ads, mem_ctx,
583                                   r->in.machine_name);
584                 if (upn) {
585                         salt = talloc_strdup(mem_ctx, upn);
586                         if (!salt) {
587                                 return false;
588                         }
589                 }
590         }
591
592         return kerberos_secrets_store_des_salt(salt);
593 }
594
595 /****************************************************************
596 ****************************************************************/
597
598 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
599                                                   struct libnet_JoinCtx *r)
600 {
601         ADS_STATUS status;
602
603         if (!r->in.ads) {
604                 status = libnet_join_connect_ads(mem_ctx, r);
605                 if (!ADS_ERR_OK(status)) {
606                         return status;
607                 }
608         }
609
610         status = libnet_join_set_machine_spn(mem_ctx, r);
611         if (!ADS_ERR_OK(status)) {
612                 libnet_join_set_error_string(mem_ctx, r,
613                         "failed to set machine spn: %s",
614                         ads_errstr(status));
615                 return status;
616         }
617
618         status = libnet_join_set_os_attributes(mem_ctx, r);
619         if (!ADS_ERR_OK(status)) {
620                 libnet_join_set_error_string(mem_ctx, r,
621                         "failed to set machine os attributes: %s",
622                         ads_errstr(status));
623                 return status;
624         }
625
626         status = libnet_join_set_machine_upn(mem_ctx, r);
627         if (!ADS_ERR_OK(status)) {
628                 libnet_join_set_error_string(mem_ctx, r,
629                         "failed to set machine upn: %s",
630                         ads_errstr(status));
631                 return status;
632         }
633
634         if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
635                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
636         }
637
638         if (!libnet_join_create_keytab(mem_ctx, r)) {
639                 libnet_join_set_error_string(mem_ctx, r,
640                         "failed to create kerberos keytab");
641                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
642         }
643
644         return ADS_SUCCESS;
645 }
646 #endif /* HAVE_ADS */
647
648 /****************************************************************
649  Store the machine password and domain SID
650 ****************************************************************/
651
652 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
653                                                  struct libnet_JoinCtx *r)
654 {
655         if (!secrets_store_domain_sid(r->out.netbios_domain_name,
656                                       r->out.domain_sid))
657         {
658                 DEBUG(1,("Failed to save domain sid\n"));
659                 return false;
660         }
661
662         if (!secrets_store_machine_password(r->in.machine_password,
663                                             r->out.netbios_domain_name,
664                                             r->in.secure_channel_type))
665         {
666                 DEBUG(1,("Failed to save machine password\n"));
667                 return false;
668         }
669
670         return true;
671 }
672
673 /****************************************************************
674  Connect dc's IPC$ share
675 ****************************************************************/
676
677 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
678                                            const char *user,
679                                            const char *pass,
680                                            bool use_kerberos,
681                                            struct cli_state **cli)
682 {
683         int flags = 0;
684
685         if (use_kerberos) {
686                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
687         }
688
689         if (use_kerberos && pass) {
690                 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
691         }
692
693         return cli_full_connection(cli, NULL,
694                                    dc,
695                                    NULL, 0,
696                                    "IPC$", "IPC",
697                                    user,
698                                    NULL,
699                                    pass,
700                                    flags,
701                                    Undefined);
702 }
703
704 /****************************************************************
705  Lookup domain dc's info
706 ****************************************************************/
707
708 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
709                                           struct libnet_JoinCtx *r,
710                                           struct cli_state **cli)
711 {
712         struct rpc_pipe_client *pipe_hnd = NULL;
713         struct policy_handle lsa_pol;
714         NTSTATUS status, result;
715         union lsa_PolicyInformation *info = NULL;
716         struct dcerpc_binding_handle *b;
717
718         status = libnet_join_connect_dc_ipc(r->in.dc_name,
719                                             r->in.admin_account,
720                                             r->in.admin_password,
721                                             r->in.use_kerberos,
722                                             cli);
723         if (!NT_STATUS_IS_OK(status)) {
724                 goto done;
725         }
726
727         status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
728                                           &pipe_hnd);
729         if (!NT_STATUS_IS_OK(status)) {
730                 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
731                         nt_errstr(status)));
732                 goto done;
733         }
734
735         b = pipe_hnd->binding_handle;
736
737         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
738                                         SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
739         if (!NT_STATUS_IS_OK(status)) {
740                 goto done;
741         }
742
743         status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
744                                              &lsa_pol,
745                                              LSA_POLICY_INFO_DNS,
746                                              &info,
747                                              &result);
748         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
749                 r->out.domain_is_ad = true;
750                 r->out.netbios_domain_name = info->dns.name.string;
751                 r->out.dns_domain_name = info->dns.dns_domain.string;
752                 r->out.forest_name = info->dns.dns_forest.string;
753                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
754                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
755         }
756
757         if (!NT_STATUS_IS_OK(status)) {
758                 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
759                                                     &lsa_pol,
760                                                     LSA_POLICY_INFO_ACCOUNT_DOMAIN,
761                                                     &info,
762                                                     &result);
763                 if (!NT_STATUS_IS_OK(status)) {
764                         goto done;
765                 }
766                 if (!NT_STATUS_IS_OK(result)) {
767                         status = result;
768                         goto done;
769                 }
770
771                 r->out.netbios_domain_name = info->account_domain.name.string;
772                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
773                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
774         }
775
776         dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
777         TALLOC_FREE(pipe_hnd);
778
779  done:
780         return status;
781 }
782
783 /****************************************************************
784  Do the domain join unsecure
785 ****************************************************************/
786
787 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
788                                                     struct libnet_JoinCtx *r,
789                                                     struct cli_state *cli)
790 {
791         struct rpc_pipe_client *pipe_hnd = NULL;
792         unsigned char orig_trust_passwd_hash[16];
793         unsigned char new_trust_passwd_hash[16];
794         fstring trust_passwd;
795         NTSTATUS status;
796
797         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
798                                           &pipe_hnd);
799         if (!NT_STATUS_IS_OK(status)) {
800                 return status;
801         }
802
803         if (!r->in.machine_password) {
804                 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
805                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
806         }
807
808         E_md4hash(r->in.machine_password, new_trust_passwd_hash);
809
810         /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
811         fstrcpy(trust_passwd, r->in.admin_password);
812         strlower_m(trust_passwd);
813
814         /*
815          * Machine names can be 15 characters, but the max length on
816          * a password is 14.  --jerry
817          */
818
819         trust_passwd[14] = '\0';
820
821         E_md4hash(trust_passwd, orig_trust_passwd_hash);
822
823         status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
824                                                     r->in.machine_name,
825                                                     orig_trust_passwd_hash,
826                                                     r->in.machine_password,
827                                                     new_trust_passwd_hash,
828                                                     r->in.secure_channel_type);
829
830         return status;
831 }
832
833 /****************************************************************
834  Do the domain join
835 ****************************************************************/
836
837 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
838                                            struct libnet_JoinCtx *r,
839                                            struct cli_state *cli)
840 {
841         struct rpc_pipe_client *pipe_hnd = NULL;
842         struct policy_handle sam_pol, domain_pol, user_pol;
843         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
844         char *acct_name;
845         struct lsa_String lsa_acct_name;
846         uint32_t user_rid;
847         uint32_t acct_flags = ACB_WSTRUST;
848         struct samr_Ids user_rids;
849         struct samr_Ids name_types;
850         union samr_UserInfo user_info;
851         struct dcerpc_binding_handle *b = NULL;
852
853         struct samr_CryptPassword crypt_pwd;
854         struct samr_CryptPasswordEx crypt_pwd_ex;
855
856         ZERO_STRUCT(sam_pol);
857         ZERO_STRUCT(domain_pol);
858         ZERO_STRUCT(user_pol);
859
860         switch (r->in.secure_channel_type) {
861         case SEC_CHAN_WKSTA:
862                 acct_flags = ACB_WSTRUST;
863                 break;
864         case SEC_CHAN_BDC:
865                 acct_flags = ACB_SVRTRUST;
866                 break;
867         default:
868                 return NT_STATUS_INVALID_PARAMETER;
869         }
870
871         if (!r->in.machine_password) {
872                 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
873                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
874         }
875
876         /* Open the domain */
877
878         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
879                                           &pipe_hnd);
880         if (!NT_STATUS_IS_OK(status)) {
881                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
882                         nt_errstr(status)));
883                 goto done;
884         }
885
886         b = pipe_hnd->binding_handle;
887
888         status = dcerpc_samr_Connect2(b, mem_ctx,
889                                       pipe_hnd->desthost,
890                                       SAMR_ACCESS_ENUM_DOMAINS
891                                       | SAMR_ACCESS_LOOKUP_DOMAIN,
892                                       &sam_pol,
893                                       &result);
894         if (!NT_STATUS_IS_OK(status)) {
895                 goto done;
896         }
897         if (!NT_STATUS_IS_OK(result)) {
898                 status = result;
899                 goto done;
900         }
901
902         status = dcerpc_samr_OpenDomain(b, mem_ctx,
903                                         &sam_pol,
904                                         SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
905                                         | SAMR_DOMAIN_ACCESS_CREATE_USER
906                                         | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
907                                         r->out.domain_sid,
908                                         &domain_pol,
909                                         &result);
910         if (!NT_STATUS_IS_OK(status)) {
911                 goto done;
912         }
913         if (!NT_STATUS_IS_OK(result)) {
914                 status = result;
915                 goto done;
916         }
917
918         /* Create domain user */
919
920         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
921         strlower_m(acct_name);
922
923         init_lsa_String(&lsa_acct_name, acct_name);
924
925         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
926                 uint32_t access_desired =
927                         SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
928                         SEC_STD_WRITE_DAC | SEC_STD_DELETE |
929                         SAMR_USER_ACCESS_SET_PASSWORD |
930                         SAMR_USER_ACCESS_GET_ATTRIBUTES |
931                         SAMR_USER_ACCESS_SET_ATTRIBUTES;
932                 uint32_t access_granted = 0;
933
934                 DEBUG(10,("Creating account with desired access mask: %d\n",
935                         access_desired));
936
937                 status = dcerpc_samr_CreateUser2(b, mem_ctx,
938                                                  &domain_pol,
939                                                  &lsa_acct_name,
940                                                  acct_flags,
941                                                  access_desired,
942                                                  &user_pol,
943                                                  &access_granted,
944                                                  &user_rid,
945                                                  &result);
946                 if (!NT_STATUS_IS_OK(status)) {
947                         goto done;
948                 }
949
950                 status = result;
951                 if (!NT_STATUS_IS_OK(status) &&
952                     !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
953
954                         DEBUG(10,("Creation of workstation account failed: %s\n",
955                                 nt_errstr(status)));
956
957                         /* If NT_STATUS_ACCESS_DENIED then we have a valid
958                            username/password combo but the user does not have
959                            administrator access. */
960
961                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
962                                 libnet_join_set_error_string(mem_ctx, r,
963                                         "User specified does not have "
964                                         "administrator privileges");
965                         }
966
967                         goto done;
968                 }
969
970                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
971                         if (!(r->in.join_flags &
972                               WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
973                                 goto done;
974                         }
975                 }
976
977                 /* We *must* do this.... don't ask... */
978
979                 if (NT_STATUS_IS_OK(status)) {
980                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
981                 }
982         }
983
984         status = dcerpc_samr_LookupNames(b, mem_ctx,
985                                          &domain_pol,
986                                          1,
987                                          &lsa_acct_name,
988                                          &user_rids,
989                                          &name_types,
990                                          &result);
991         if (!NT_STATUS_IS_OK(status)) {
992                 goto done;
993         }
994         if (!NT_STATUS_IS_OK(result)) {
995                 status = result;
996                 goto done;
997         }
998
999         if (name_types.ids[0] != SID_NAME_USER) {
1000                 DEBUG(0,("%s is not a user account (type=%d)\n",
1001                         acct_name, name_types.ids[0]));
1002                 status = NT_STATUS_INVALID_WORKSTATION;
1003                 goto done;
1004         }
1005
1006         user_rid = user_rids.ids[0];
1007
1008         /* Open handle on user */
1009
1010         status = dcerpc_samr_OpenUser(b, mem_ctx,
1011                                       &domain_pol,
1012                                       SEC_FLAG_MAXIMUM_ALLOWED,
1013                                       user_rid,
1014                                       &user_pol,
1015                                       &result);
1016         if (!NT_STATUS_IS_OK(status)) {
1017                 goto done;
1018         }
1019         if (!NT_STATUS_IS_OK(result)) {
1020                 status = result;
1021                 goto done;
1022         }
1023
1024         /* Fill in the additional account flags now */
1025
1026         acct_flags |= ACB_PWNOEXP;
1027
1028         /* Set account flags on machine account */
1029         ZERO_STRUCT(user_info.info16);
1030         user_info.info16.acct_flags = acct_flags;
1031
1032         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1033                                          &user_pol,
1034                                          16,
1035                                          &user_info,
1036                                          &result);
1037         if (!NT_STATUS_IS_OK(status)) {
1038                 dcerpc_samr_DeleteUser(b, mem_ctx,
1039                                        &user_pol,
1040                                        &result);
1041
1042                 libnet_join_set_error_string(mem_ctx, r,
1043                         "Failed to set account flags for machine account (%s)\n",
1044                         nt_errstr(status));
1045                 goto done;
1046         }
1047
1048         if (!NT_STATUS_IS_OK(result)) {
1049                 status = result;
1050
1051                 dcerpc_samr_DeleteUser(b, mem_ctx,
1052                                        &user_pol,
1053                                        &result);
1054
1055                 libnet_join_set_error_string(mem_ctx, r,
1056                         "Failed to set account flags for machine account (%s)\n",
1057                         nt_errstr(status));
1058                 goto done;
1059         }
1060
1061         /* Set password on machine account - first try level 26 */
1062
1063         init_samr_CryptPasswordEx(r->in.machine_password,
1064                                   &cli->user_session_key,
1065                                   &crypt_pwd_ex);
1066
1067         user_info.info26.password = crypt_pwd_ex;
1068         user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1069
1070         status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1071                                           &user_pol,
1072                                           26,
1073                                           &user_info,
1074                                           &result);
1075
1076         if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1077
1078                 /* retry with level 24 */
1079
1080                 init_samr_CryptPassword(r->in.machine_password,
1081                                         &cli->user_session_key,
1082                                         &crypt_pwd);
1083
1084                 user_info.info24.password = crypt_pwd;
1085                 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1086
1087                 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1088                                                   &user_pol,
1089                                                   24,
1090                                                   &user_info,
1091                                                   &result);
1092         }
1093
1094         if (!NT_STATUS_IS_OK(status)) {
1095
1096                 dcerpc_samr_DeleteUser(b, mem_ctx,
1097                                        &user_pol,
1098                                        &result);
1099
1100                 libnet_join_set_error_string(mem_ctx, r,
1101                         "Failed to set password for machine account (%s)\n",
1102                         nt_errstr(status));
1103                 goto done;
1104         }
1105         if (!NT_STATUS_IS_OK(result)) {
1106                 status = result;
1107
1108                 dcerpc_samr_DeleteUser(b, mem_ctx,
1109                                        &user_pol,
1110                                        &result);
1111
1112                 libnet_join_set_error_string(mem_ctx, r,
1113                         "Failed to set password for machine account (%s)\n",
1114                         nt_errstr(status));
1115                 goto done;
1116         }
1117
1118         status = NT_STATUS_OK;
1119
1120  done:
1121         if (!pipe_hnd) {
1122                 return status;
1123         }
1124
1125         if (is_valid_policy_hnd(&sam_pol)) {
1126                 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1127         }
1128         if (is_valid_policy_hnd(&domain_pol)) {
1129                 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1130         }
1131         if (is_valid_policy_hnd(&user_pol)) {
1132                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1133         }
1134         TALLOC_FREE(pipe_hnd);
1135
1136         return status;
1137 }
1138
1139 /****************************************************************
1140 ****************************************************************/
1141
1142 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1143                         const char *machine_name,
1144                         const char *dc_name)
1145 {
1146         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1147         struct cli_state *cli = NULL;
1148         struct rpc_pipe_client *pipe_hnd = NULL;
1149         struct rpc_pipe_client *netlogon_pipe = NULL;
1150         NTSTATUS status;
1151         char *machine_password = NULL;
1152         char *machine_account = NULL;
1153
1154         if (!dc_name) {
1155                 return NT_STATUS_INVALID_PARAMETER;
1156         }
1157
1158         if (!secrets_init()) {
1159                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1160         }
1161
1162         machine_password = secrets_fetch_machine_password(netbios_domain_name,
1163                                                           NULL, NULL);
1164         if (!machine_password) {
1165                 return NT_STATUS_NO_TRUST_LSA_SECRET;
1166         }
1167
1168         if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1169                 SAFE_FREE(machine_password);
1170                 return NT_STATUS_NO_MEMORY;
1171         }
1172
1173         status = cli_full_connection(&cli, NULL,
1174                                      dc_name,
1175                                      NULL, 0,
1176                                      "IPC$", "IPC",
1177                                      machine_account,
1178                                      NULL,
1179                                      machine_password,
1180                                      0,
1181                                      Undefined);
1182         free(machine_account);
1183         free(machine_password);
1184
1185         if (!NT_STATUS_IS_OK(status)) {
1186                 status = cli_full_connection(&cli, NULL,
1187                                              dc_name,
1188                                              NULL, 0,
1189                                              "IPC$", "IPC",
1190                                              "",
1191                                              NULL,
1192                                              "",
1193                                              0,
1194                                              Undefined);
1195         }
1196
1197         if (!NT_STATUS_IS_OK(status)) {
1198                 return status;
1199         }
1200
1201         status = get_schannel_session_key(cli, netbios_domain_name,
1202                                           &neg_flags, &netlogon_pipe);
1203         if (!NT_STATUS_IS_OK(status)) {
1204                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1205                         cli_shutdown(cli);
1206                         return NT_STATUS_OK;
1207                 }
1208
1209                 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1210                         "key from server %s for domain %s. Error was %s\n",
1211                 cli->desthost, netbios_domain_name, nt_errstr(status)));
1212                 cli_shutdown(cli);
1213                 return status;
1214         }
1215
1216         if (!lp_client_schannel()) {
1217                 cli_shutdown(cli);
1218                 return NT_STATUS_OK;
1219         }
1220
1221         status = cli_rpc_pipe_open_schannel_with_key(
1222                 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1223                 DCERPC_AUTH_LEVEL_PRIVACY,
1224                 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1225
1226         cli_shutdown(cli);
1227
1228         if (!NT_STATUS_IS_OK(status)) {
1229                 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1230                         "on netlogon pipe to server %s for domain %s. "
1231                         "Error was %s\n",
1232                         cli->desthost, netbios_domain_name, nt_errstr(status)));
1233                 return status;
1234         }
1235
1236         return NT_STATUS_OK;
1237 }
1238
1239 /****************************************************************
1240 ****************************************************************/
1241
1242 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1243                                       struct libnet_JoinCtx *r)
1244 {
1245         NTSTATUS status;
1246
1247         status = libnet_join_ok(r->out.netbios_domain_name,
1248                                 r->in.machine_name,
1249                                 r->in.dc_name);
1250         if (!NT_STATUS_IS_OK(status)) {
1251                 libnet_join_set_error_string(mem_ctx, r,
1252                         "failed to verify domain membership after joining: %s",
1253                         get_friendly_nt_error_msg(status));
1254                 return WERR_SETUP_NOT_JOINED;
1255         }
1256
1257         return WERR_OK;
1258 }
1259
1260 /****************************************************************
1261 ****************************************************************/
1262
1263 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1264                                                     struct libnet_UnjoinCtx *r)
1265 {
1266         if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1267                 return false;
1268         }
1269
1270         if (!secrets_delete_domain_sid(lp_workgroup())) {
1271                 return false;
1272         }
1273
1274         return true;
1275 }
1276
1277 /****************************************************************
1278 ****************************************************************/
1279
1280 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1281                                              struct libnet_UnjoinCtx *r)
1282 {
1283         struct cli_state *cli = NULL;
1284         struct rpc_pipe_client *pipe_hnd = NULL;
1285         struct policy_handle sam_pol, domain_pol, user_pol;
1286         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1287         char *acct_name;
1288         uint32_t user_rid;
1289         struct lsa_String lsa_acct_name;
1290         struct samr_Ids user_rids;
1291         struct samr_Ids name_types;
1292         union samr_UserInfo *info = NULL;
1293         struct dcerpc_binding_handle *b;
1294
1295         ZERO_STRUCT(sam_pol);
1296         ZERO_STRUCT(domain_pol);
1297         ZERO_STRUCT(user_pol);
1298
1299         status = libnet_join_connect_dc_ipc(r->in.dc_name,
1300                                             r->in.admin_account,
1301                                             r->in.admin_password,
1302                                             r->in.use_kerberos,
1303                                             &cli);
1304         if (!NT_STATUS_IS_OK(status)) {
1305                 goto done;
1306         }
1307
1308         /* Open the domain */
1309
1310         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1311                                           &pipe_hnd);
1312         if (!NT_STATUS_IS_OK(status)) {
1313                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1314                         nt_errstr(status)));
1315                 goto done;
1316         }
1317
1318         b = pipe_hnd->binding_handle;
1319
1320         status = dcerpc_samr_Connect2(b, mem_ctx,
1321                                       pipe_hnd->desthost,
1322                                       SEC_FLAG_MAXIMUM_ALLOWED,
1323                                       &sam_pol,
1324                                       &result);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 goto done;
1327         }
1328         if (!NT_STATUS_IS_OK(result)) {
1329                 status = result;
1330                 goto done;
1331         }
1332
1333         status = dcerpc_samr_OpenDomain(b, mem_ctx,
1334                                         &sam_pol,
1335                                         SEC_FLAG_MAXIMUM_ALLOWED,
1336                                         r->in.domain_sid,
1337                                         &domain_pol,
1338                                         &result);
1339         if (!NT_STATUS_IS_OK(status)) {
1340                 goto done;
1341         }
1342         if (!NT_STATUS_IS_OK(result)) {
1343                 status = result;
1344                 goto done;
1345         }
1346
1347         /* Create domain user */
1348
1349         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1350         strlower_m(acct_name);
1351
1352         init_lsa_String(&lsa_acct_name, acct_name);
1353
1354         status = dcerpc_samr_LookupNames(b, mem_ctx,
1355                                          &domain_pol,
1356                                          1,
1357                                          &lsa_acct_name,
1358                                          &user_rids,
1359                                          &name_types,
1360                                          &result);
1361
1362         if (!NT_STATUS_IS_OK(status)) {
1363                 goto done;
1364         }
1365         if (!NT_STATUS_IS_OK(result)) {
1366                 status = result;
1367                 goto done;
1368         }
1369
1370         if (name_types.ids[0] != SID_NAME_USER) {
1371                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1372                         name_types.ids[0]));
1373                 status = NT_STATUS_INVALID_WORKSTATION;
1374                 goto done;
1375         }
1376
1377         user_rid = user_rids.ids[0];
1378
1379         /* Open handle on user */
1380
1381         status = dcerpc_samr_OpenUser(b, mem_ctx,
1382                                       &domain_pol,
1383                                       SEC_FLAG_MAXIMUM_ALLOWED,
1384                                       user_rid,
1385                                       &user_pol,
1386                                       &result);
1387         if (!NT_STATUS_IS_OK(status)) {
1388                 goto done;
1389         }
1390         if (!NT_STATUS_IS_OK(result)) {
1391                 status = result;
1392                 goto done;
1393         }
1394
1395         /* Get user info */
1396
1397         status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1398                                            &user_pol,
1399                                            16,
1400                                            &info,
1401                                            &result);
1402         if (!NT_STATUS_IS_OK(status)) {
1403                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1404                 goto done;
1405         }
1406         if (!NT_STATUS_IS_OK(result)) {
1407                 status = result;
1408                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1409                 goto done;
1410         }
1411
1412         /* now disable and setuser info */
1413
1414         info->info16.acct_flags |= ACB_DISABLED;
1415
1416         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1417                                          &user_pol,
1418                                          16,
1419                                          info,
1420                                          &result);
1421         if (!NT_STATUS_IS_OK(status)) {
1422                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1423                 goto done;
1424         }
1425         if (!NT_STATUS_IS_OK(result)) {
1426                 status = result;
1427                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1428                 goto done;
1429         }
1430         status = result;
1431         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1432
1433 done:
1434         if (pipe_hnd) {
1435                 if (is_valid_policy_hnd(&domain_pol)) {
1436                         dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1437                 }
1438                 if (is_valid_policy_hnd(&sam_pol)) {
1439                         dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1440                 }
1441                 TALLOC_FREE(pipe_hnd);
1442         }
1443
1444         if (cli) {
1445                 cli_shutdown(cli);
1446         }
1447
1448         return status;
1449 }
1450
1451 /****************************************************************
1452 ****************************************************************/
1453
1454 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1455 {
1456         WERROR werr;
1457         struct smbconf_ctx *ctx;
1458
1459         werr = smbconf_init_reg(r, &ctx, NULL);
1460         if (!W_ERROR_IS_OK(werr)) {
1461                 goto done;
1462         }
1463
1464         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1465
1466                 werr = smbconf_set_global_parameter(ctx, "security", "user");
1467                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1468
1469                 werr = smbconf_set_global_parameter(ctx, "workgroup",
1470                                                     r->in.domain_name);
1471
1472                 smbconf_delete_global_parameter(ctx, "realm");
1473                 goto done;
1474         }
1475
1476         werr = smbconf_set_global_parameter(ctx, "security", "domain");
1477         W_ERROR_NOT_OK_GOTO_DONE(werr);
1478
1479         werr = smbconf_set_global_parameter(ctx, "workgroup",
1480                                             r->out.netbios_domain_name);
1481         W_ERROR_NOT_OK_GOTO_DONE(werr);
1482
1483         if (r->out.domain_is_ad) {
1484                 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1485                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1486
1487                 werr = smbconf_set_global_parameter(ctx, "realm",
1488                                                     r->out.dns_domain_name);
1489                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1490         }
1491
1492  done:
1493         smbconf_shutdown(ctx);
1494         return werr;
1495 }
1496
1497 /****************************************************************
1498 ****************************************************************/
1499
1500 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1501 {
1502         WERROR werr = WERR_OK;
1503         struct smbconf_ctx *ctx;
1504
1505         werr = smbconf_init_reg(r, &ctx, NULL);
1506         if (!W_ERROR_IS_OK(werr)) {
1507                 goto done;
1508         }
1509
1510         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1511
1512                 werr = smbconf_set_global_parameter(ctx, "security", "user");
1513                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1514
1515                 werr = smbconf_delete_global_parameter(ctx, "workgroup");
1516                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1517
1518                 smbconf_delete_global_parameter(ctx, "realm");
1519         }
1520
1521  done:
1522         smbconf_shutdown(ctx);
1523         return werr;
1524 }
1525
1526 /****************************************************************
1527 ****************************************************************/
1528
1529 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1530 {
1531         WERROR werr;
1532
1533         if (!W_ERROR_IS_OK(r->out.result)) {
1534                 return r->out.result;
1535         }
1536
1537         if (!r->in.modify_config) {
1538                 return WERR_OK;
1539         }
1540
1541         werr = do_join_modify_vals_config(r);
1542         if (!W_ERROR_IS_OK(werr)) {
1543                 return werr;
1544         }
1545
1546         lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1547
1548         r->out.modified_config = true;
1549         r->out.result = werr;
1550
1551         return werr;
1552 }
1553
1554 /****************************************************************
1555 ****************************************************************/
1556
1557 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1558 {
1559         WERROR werr;
1560
1561         if (!W_ERROR_IS_OK(r->out.result)) {
1562                 return r->out.result;
1563         }
1564
1565         if (!r->in.modify_config) {
1566                 return WERR_OK;
1567         }
1568
1569         werr = do_unjoin_modify_vals_config(r);
1570         if (!W_ERROR_IS_OK(werr)) {
1571                 return werr;
1572         }
1573
1574         lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1575
1576         r->out.modified_config = true;
1577         r->out.result = werr;
1578
1579         return werr;
1580 }
1581
1582 /****************************************************************
1583 ****************************************************************/
1584
1585 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1586                                    const char *domain_str,
1587                                    const char **domain_p,
1588                                    const char **dc_p)
1589 {
1590         char *domain = NULL;
1591         char *dc = NULL;
1592         const char *p = NULL;
1593
1594         if (!domain_str || !domain_p || !dc_p) {
1595                 return false;
1596         }
1597
1598         p = strchr_m(domain_str, '\\');
1599
1600         if (p != NULL) {
1601                 domain = talloc_strndup(mem_ctx, domain_str,
1602                                          PTR_DIFF(p, domain_str));
1603                 dc = talloc_strdup(mem_ctx, p+1);
1604                 if (!dc) {
1605                         return false;
1606                 }
1607         } else {
1608                 domain = talloc_strdup(mem_ctx, domain_str);
1609                 dc = NULL;
1610         }
1611         if (!domain) {
1612                 return false;
1613         }
1614
1615         *domain_p = domain;
1616
1617         if (!*dc_p && dc) {
1618                 *dc_p = dc;
1619         }
1620
1621         return true;
1622 }
1623
1624 /****************************************************************
1625 ****************************************************************/
1626
1627 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1628                                          struct libnet_JoinCtx *r)
1629 {
1630         if (!r->in.domain_name) {
1631                 libnet_join_set_error_string(mem_ctx, r,
1632                         "No domain name defined");
1633                 return WERR_INVALID_PARAM;
1634         }
1635
1636         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1637                                     &r->in.domain_name,
1638                                     &r->in.dc_name)) {
1639                 libnet_join_set_error_string(mem_ctx, r,
1640                         "Failed to parse domain name");
1641                 return WERR_INVALID_PARAM;
1642         }
1643
1644         if (IS_DC) {
1645                 return WERR_SETUP_DOMAIN_CONTROLLER;
1646         }
1647
1648         if (!secrets_init()) {
1649                 libnet_join_set_error_string(mem_ctx, r,
1650                         "Unable to open secrets database");
1651                 return WERR_CAN_NOT_COMPLETE;
1652         }
1653
1654         return WERR_OK;
1655 }
1656
1657 /****************************************************************
1658 ****************************************************************/
1659
1660 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1661 {
1662         NTSTATUS status;
1663
1664         /* Try adding dom admins to builtin\admins. Only log failures. */
1665         status = create_builtin_administrators(domain_sid);
1666         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1667                 DEBUG(10,("Unable to auto-add domain administrators to "
1668                           "BUILTIN\\Administrators during join because "
1669                           "winbindd must be running."));
1670         } else if (!NT_STATUS_IS_OK(status)) {
1671                 DEBUG(5, ("Failed to auto-add domain administrators to "
1672                           "BUILTIN\\Administrators during join: %s\n",
1673                           nt_errstr(status)));
1674         }
1675
1676         /* Try adding dom users to builtin\users. Only log failures. */
1677         status = create_builtin_users(domain_sid);
1678         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1679                 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1680                           "during join because winbindd must be running."));
1681         } else if (!NT_STATUS_IS_OK(status)) {
1682                 DEBUG(5, ("Failed to auto-add domain administrators to "
1683                           "BUILTIN\\Administrators during join: %s\n",
1684                           nt_errstr(status)));
1685         }
1686 }
1687
1688 /****************************************************************
1689 ****************************************************************/
1690
1691 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1692                                           struct libnet_JoinCtx *r)
1693 {
1694         WERROR werr;
1695
1696         if (!W_ERROR_IS_OK(r->out.result)) {
1697                 return r->out.result;
1698         }
1699
1700         werr = do_JoinConfig(r);
1701         if (!W_ERROR_IS_OK(werr)) {
1702                 return werr;
1703         }
1704
1705         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1706                 return WERR_OK;
1707         }
1708
1709         saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1710         if (r->out.dns_domain_name) {
1711                 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1712         }
1713
1714 #ifdef HAVE_ADS
1715         if (r->out.domain_is_ad &&
1716             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1717                 ADS_STATUS ads_status;
1718
1719                 ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
1720                 if (!ADS_ERR_OK(ads_status)) {
1721                         return WERR_GENERAL_FAILURE;
1722                 }
1723         }
1724 #endif /* HAVE_ADS */
1725
1726         libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1727
1728         return WERR_OK;
1729 }
1730
1731 /****************************************************************
1732 ****************************************************************/
1733
1734 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1735 {
1736         const char *krb5_cc_env = NULL;
1737
1738         if (r->in.ads) {
1739                 ads_destroy(&r->in.ads);
1740         }
1741
1742         krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1743         if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1744                 unsetenv(KRB5_ENV_CCNAME);
1745         }
1746
1747         return 0;
1748 }
1749
1750 /****************************************************************
1751 ****************************************************************/
1752
1753 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1754 {
1755         const char *krb5_cc_env = NULL;
1756
1757         if (r->in.ads) {
1758                 ads_destroy(&r->in.ads);
1759         }
1760
1761         krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1762         if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1763                 unsetenv(KRB5_ENV_CCNAME);
1764         }
1765
1766         return 0;
1767 }
1768
1769 /****************************************************************
1770 ****************************************************************/
1771
1772 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1773                            struct libnet_JoinCtx **r)
1774 {
1775         struct libnet_JoinCtx *ctx;
1776         const char *krb5_cc_env = NULL;
1777
1778         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1779         if (!ctx) {
1780                 return WERR_NOMEM;
1781         }
1782
1783         talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1784
1785         ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1786         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1787
1788         krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1789         if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1790                 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1791                 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1792                 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1793         }
1794
1795         ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1796
1797         *r = ctx;
1798
1799         return WERR_OK;
1800 }
1801
1802 /****************************************************************
1803 ****************************************************************/
1804
1805 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1806                              struct libnet_UnjoinCtx **r)
1807 {
1808         struct libnet_UnjoinCtx *ctx;
1809         const char *krb5_cc_env = NULL;
1810
1811         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1812         if (!ctx) {
1813                 return WERR_NOMEM;
1814         }
1815
1816         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1817
1818         ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1819         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1820
1821         krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1822         if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1823                 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1824                 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1825                 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1826         }
1827
1828         *r = ctx;
1829
1830         return WERR_OK;
1831 }
1832
1833 /****************************************************************
1834 ****************************************************************/
1835
1836 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1837                                        struct libnet_JoinCtx *r)
1838 {
1839         bool valid_security = false;
1840         bool valid_workgroup = false;
1841         bool valid_realm = false;
1842
1843         /* check if configuration is already set correctly */
1844
1845         valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1846
1847         switch (r->out.domain_is_ad) {
1848                 case false:
1849                         valid_security = (lp_security() == SEC_DOMAIN);
1850                         if (valid_workgroup && valid_security) {
1851                                 /* nothing to be done */
1852                                 return WERR_OK;
1853                         }
1854                         break;
1855                 case true:
1856                         valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1857                         switch (lp_security()) {
1858                         case SEC_DOMAIN:
1859                         case SEC_ADS:
1860                                 valid_security = true;
1861                         }
1862
1863                         if (valid_workgroup && valid_realm && valid_security) {
1864                                 /* nothing to be done */
1865                                 return WERR_OK;
1866                         }
1867                         break;
1868         }
1869
1870         /* check if we are supposed to manipulate configuration */
1871
1872         if (!r->in.modify_config) {
1873
1874                 char *wrong_conf = talloc_strdup(mem_ctx, "");
1875
1876                 if (!valid_workgroup) {
1877                         wrong_conf = talloc_asprintf_append(wrong_conf,
1878                                 "\"workgroup\" set to '%s', should be '%s'",
1879                                 lp_workgroup(), r->out.netbios_domain_name);
1880                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1881                 }
1882
1883                 if (!valid_realm) {
1884                         wrong_conf = talloc_asprintf_append(wrong_conf,
1885                                 "\"realm\" set to '%s', should be '%s'",
1886                                 lp_realm(), r->out.dns_domain_name);
1887                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1888                 }
1889
1890                 if (!valid_security) {
1891                         const char *sec = NULL;
1892                         switch (lp_security()) {
1893                         case SEC_SHARE: sec = "share"; break;
1894                         case SEC_USER:  sec = "user"; break;
1895                         case SEC_DOMAIN: sec = "domain"; break;
1896                         case SEC_ADS: sec = "ads"; break;
1897                         }
1898                         wrong_conf = talloc_asprintf_append(wrong_conf,
1899                                 "\"security\" set to '%s', should be %s",
1900                                 sec, r->out.domain_is_ad ?
1901                                 "either 'domain' or 'ads'" : "'domain'");
1902                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1903                 }
1904
1905                 libnet_join_set_error_string(mem_ctx, r,
1906                         "Invalid configuration (%s) and configuration modification "
1907                         "was not requested", wrong_conf);
1908                 return WERR_CAN_NOT_COMPLETE;
1909         }
1910
1911         /* check if we are able to manipulate configuration */
1912
1913         if (!lp_config_backend_is_registry()) {
1914                 libnet_join_set_error_string(mem_ctx, r,
1915                         "Configuration manipulation requested but not "
1916                         "supported by backend");
1917                 return WERR_NOT_SUPPORTED;
1918         }
1919
1920         return WERR_OK;
1921 }
1922
1923 /****************************************************************
1924 ****************************************************************/
1925
1926 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1927                                 struct libnet_JoinCtx *r)
1928 {
1929         NTSTATUS status;
1930         WERROR werr;
1931         struct cli_state *cli = NULL;
1932 #ifdef HAVE_ADS
1933         ADS_STATUS ads_status;
1934 #endif /* HAVE_ADS */
1935
1936         if (!r->in.dc_name) {
1937                 struct netr_DsRGetDCNameInfo *info;
1938                 const char *dc;
1939                 status = dsgetdcname(mem_ctx,
1940                                      r->in.msg_ctx,
1941                                      r->in.domain_name,
1942                                      NULL,
1943                                      NULL,
1944                                      DS_FORCE_REDISCOVERY |
1945                                      DS_DIRECTORY_SERVICE_REQUIRED |
1946                                      DS_WRITABLE_REQUIRED |
1947                                      DS_RETURN_DNS_NAME,
1948                                      &info);
1949                 if (!NT_STATUS_IS_OK(status)) {
1950                         libnet_join_set_error_string(mem_ctx, r,
1951                                 "failed to find DC for domain %s",
1952                                 r->in.domain_name,
1953                                 get_friendly_nt_error_msg(status));
1954                         return WERR_DCNOTFOUND;
1955                 }
1956
1957                 dc = strip_hostname(info->dc_unc);
1958                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
1959                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1960         }
1961
1962         status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1963         if (!NT_STATUS_IS_OK(status)) {
1964                 libnet_join_set_error_string(mem_ctx, r,
1965                         "failed to lookup DC info for domain '%s' over rpc: %s",
1966                         r->in.domain_name, get_friendly_nt_error_msg(status));
1967                 return ntstatus_to_werror(status);
1968         }
1969
1970         werr = libnet_join_check_config(mem_ctx, r);
1971         if (!W_ERROR_IS_OK(werr)) {
1972                 goto done;
1973         }
1974
1975 #ifdef HAVE_ADS
1976         if (r->out.domain_is_ad && r->in.account_ou &&
1977             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1978
1979                 ads_status = libnet_join_connect_ads(mem_ctx, r);
1980                 if (!ADS_ERR_OK(ads_status)) {
1981                         return WERR_DEFAULT_JOIN_REQUIRED;
1982                 }
1983
1984                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1985                 if (!ADS_ERR_OK(ads_status)) {
1986                         libnet_join_set_error_string(mem_ctx, r,
1987                                 "failed to precreate account in ou %s: %s",
1988                                 r->in.account_ou,
1989                                 ads_errstr(ads_status));
1990                         return WERR_DEFAULT_JOIN_REQUIRED;
1991                 }
1992
1993                 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1994         }
1995 #endif /* HAVE_ADS */
1996
1997         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
1998             (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
1999                 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2000         } else {
2001                 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2002         }
2003         if (!NT_STATUS_IS_OK(status)) {
2004                 libnet_join_set_error_string(mem_ctx, r,
2005                         "failed to join domain '%s' over rpc: %s",
2006                         r->in.domain_name, get_friendly_nt_error_msg(status));
2007                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2008                         return WERR_SETUP_ALREADY_JOINED;
2009                 }
2010                 werr = ntstatus_to_werror(status);
2011                 goto done;
2012         }
2013
2014         if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2015                 werr = WERR_SETUP_NOT_JOINED;
2016                 goto done;
2017         }
2018
2019         werr = WERR_OK;
2020
2021  done:
2022         if (cli) {
2023                 cli_shutdown(cli);
2024         }
2025
2026         return werr;
2027 }
2028
2029 /****************************************************************
2030 ****************************************************************/
2031
2032 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2033                                    struct libnet_JoinCtx *r)
2034 {
2035         WERROR werr;
2036         struct libnet_UnjoinCtx *u = NULL;
2037
2038         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2039         if (!W_ERROR_IS_OK(werr)) {
2040                 return werr;
2041         }
2042
2043         u->in.debug             = r->in.debug;
2044         u->in.dc_name           = r->in.dc_name;
2045         u->in.domain_name       = r->in.domain_name;
2046         u->in.admin_account     = r->in.admin_account;
2047         u->in.admin_password    = r->in.admin_password;
2048         u->in.modify_config     = r->in.modify_config;
2049         u->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2050                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2051
2052         werr = libnet_Unjoin(mem_ctx, u);
2053         TALLOC_FREE(u);
2054
2055         return werr;
2056 }
2057
2058 /****************************************************************
2059 ****************************************************************/
2060
2061 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2062                    struct libnet_JoinCtx *r)
2063 {
2064         WERROR werr;
2065
2066         if (r->in.debug) {
2067                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2068         }
2069
2070         werr = libnet_join_pre_processing(mem_ctx, r);
2071         if (!W_ERROR_IS_OK(werr)) {
2072                 goto done;
2073         }
2074
2075         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2076                 werr = libnet_DomainJoin(mem_ctx, r);
2077                 if (!W_ERROR_IS_OK(werr)) {
2078                         goto done;
2079                 }
2080         }
2081
2082         werr = libnet_join_post_processing(mem_ctx, r);
2083         if (!W_ERROR_IS_OK(werr)) {
2084                 goto done;
2085         }
2086
2087         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2088                 werr = libnet_join_post_verify(mem_ctx, r);
2089                 if (!W_ERROR_IS_OK(werr)) {
2090                         libnet_join_rollback(mem_ctx, r);
2091                 }
2092         }
2093
2094  done:
2095         r->out.result = werr;
2096
2097         if (r->in.debug) {
2098                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2099         }
2100         return werr;
2101 }
2102
2103 /****************************************************************
2104 ****************************************************************/
2105
2106 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2107                                   struct libnet_UnjoinCtx *r)
2108 {
2109         NTSTATUS status;
2110
2111         if (!r->in.domain_sid) {
2112                 struct dom_sid sid;
2113                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2114                         libnet_unjoin_set_error_string(mem_ctx, r,
2115                                 "Unable to fetch domain sid: are we joined?");
2116                         return WERR_SETUP_NOT_JOINED;
2117                 }
2118                 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2119                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2120         }
2121
2122         if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && 
2123             !r->in.delete_machine_account) {
2124                 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2125                 return WERR_OK;
2126         }
2127
2128         if (!r->in.dc_name) {
2129                 struct netr_DsRGetDCNameInfo *info;
2130                 const char *dc;
2131                 status = dsgetdcname(mem_ctx,
2132                                      r->in.msg_ctx,
2133                                      r->in.domain_name,
2134                                      NULL,
2135                                      NULL,
2136                                      DS_DIRECTORY_SERVICE_REQUIRED |
2137                                      DS_WRITABLE_REQUIRED |
2138                                      DS_RETURN_DNS_NAME,
2139                                      &info);
2140                 if (!NT_STATUS_IS_OK(status)) {
2141                         libnet_unjoin_set_error_string(mem_ctx, r,
2142                                 "failed to find DC for domain %s",
2143                                 r->in.domain_name,
2144                                 get_friendly_nt_error_msg(status));
2145                         return WERR_DCNOTFOUND;
2146                 }
2147
2148                 dc = strip_hostname(info->dc_unc);
2149                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2150                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2151         }
2152
2153 #ifdef HAVE_ADS
2154         /* for net ads leave, try to delete the account.  If it works, 
2155            no sense in disabling.  If it fails, we can still try to 
2156            disable it. jmcd */
2157
2158         if (r->in.delete_machine_account) {
2159                 ADS_STATUS ads_status;
2160                 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2161                 if (ADS_ERR_OK(ads_status)) {
2162                         /* dirty hack */
2163                         r->out.dns_domain_name = 
2164                                 talloc_strdup(mem_ctx,
2165                                               r->in.ads->server.realm);
2166                         ads_status = 
2167                                 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2168                 }
2169                 if (!ADS_ERR_OK(ads_status)) {
2170                         libnet_unjoin_set_error_string(mem_ctx, r,
2171                                 "failed to remove machine account from AD: %s",
2172                                 ads_errstr(ads_status));
2173                 } else {
2174                         r->out.deleted_machine_account = true;
2175                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2176                         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2177                         return WERR_OK;
2178                 }
2179         }
2180 #endif /* HAVE_ADS */
2181
2182         /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means 
2183            "disable".  */
2184         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2185                 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2186                 if (!NT_STATUS_IS_OK(status)) {
2187                         libnet_unjoin_set_error_string(mem_ctx, r,
2188                                 "failed to disable machine account via rpc: %s",
2189                                 get_friendly_nt_error_msg(status));
2190                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2191                                 return WERR_SETUP_NOT_JOINED;
2192                         }
2193                         return ntstatus_to_werror(status);
2194                 }
2195
2196                 r->out.disabled_machine_account = true;
2197         }
2198
2199         /* If disable succeeded or was not requested at all, we 
2200            should be getting rid of our end of things */
2201
2202         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2203
2204         return WERR_OK;
2205 }
2206
2207 /****************************************************************
2208 ****************************************************************/
2209
2210 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2211                                            struct libnet_UnjoinCtx *r)
2212 {
2213         if (!r->in.domain_name) {
2214                 libnet_unjoin_set_error_string(mem_ctx, r,
2215                         "No domain name defined");
2216                 return WERR_INVALID_PARAM;
2217         }
2218
2219         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2220                                     &r->in.domain_name,
2221                                     &r->in.dc_name)) {
2222                 libnet_unjoin_set_error_string(mem_ctx, r,
2223                         "Failed to parse domain name");
2224                 return WERR_INVALID_PARAM;
2225         }
2226
2227         if (IS_DC) {
2228                 return WERR_SETUP_DOMAIN_CONTROLLER;
2229         }
2230
2231         if (!secrets_init()) {
2232                 libnet_unjoin_set_error_string(mem_ctx, r,
2233                         "Unable to open secrets database");
2234                 return WERR_CAN_NOT_COMPLETE;
2235         }
2236
2237         return WERR_OK;
2238 }
2239
2240 /****************************************************************
2241 ****************************************************************/
2242
2243 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2244                                             struct libnet_UnjoinCtx *r)
2245 {
2246         saf_delete(r->out.netbios_domain_name);
2247         saf_delete(r->out.dns_domain_name);
2248
2249         return libnet_unjoin_config(r);
2250 }
2251
2252 /****************************************************************
2253 ****************************************************************/
2254
2255 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2256                      struct libnet_UnjoinCtx *r)
2257 {
2258         WERROR werr;
2259
2260         if (r->in.debug) {
2261                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2262         }
2263
2264         werr = libnet_unjoin_pre_processing(mem_ctx, r);
2265         if (!W_ERROR_IS_OK(werr)) {
2266                 goto done;
2267         }
2268
2269         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2270                 werr = libnet_DomainUnjoin(mem_ctx, r);
2271                 if (!W_ERROR_IS_OK(werr)) {
2272                         libnet_unjoin_config(r);
2273                         goto done;
2274                 }
2275         }
2276
2277         werr = libnet_unjoin_post_processing(mem_ctx, r);
2278         if (!W_ERROR_IS_OK(werr)) {
2279                 goto done;
2280         }
2281
2282  done:
2283         r->out.result = werr;
2284
2285         if (r->in.debug) {
2286                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2287         }
2288
2289         return werr;
2290 }