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