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