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