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