s3-libnet: Add missing format element
[samba.git] / source3 / libnet / libnet_join.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet Join Support
4  *  Copyright (C) Gerald (Jerry) Carter 2006
5  *  Copyright (C) Guenther Deschner 2007-2008
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "ads.h"
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
35 #include "secrets.h"
36 #include "rpc_client/init_lsa.h"
37 #include "rpc_client/cli_pipe.h"
38 #include "../libcli/security/security.h"
39 #include "passdb.h"
40 #include "libsmb/libsmb.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/param/loadparm.h"
43 #include "libcli/auth/netlogon_creds_cli.h"
44 #include "auth/credentials/credentials.h"
45 #include "krb5_env.h"
46
47 /****************************************************************
48 ****************************************************************/
49
50 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
51         do { \
52                 char *str = NULL; \
53                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
54                 DEBUG(1,("libnet_Join:\n%s", str)); \
55                 TALLOC_FREE(str); \
56         } while (0)
57
58 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
59         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
60 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
61         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
62
63 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
64         do { \
65                 char *str = NULL; \
66                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
67                 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
68                 TALLOC_FREE(str); \
69         } while (0)
70
71 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
72         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
73 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
74         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
75
76 /****************************************************************
77 ****************************************************************/
78
79 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
80                                          struct libnet_JoinCtx *r,
81                                          const char *format, ...)
82 {
83         va_list args;
84
85         if (r->out.error_string) {
86                 return;
87         }
88
89         va_start(args, format);
90         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
91         va_end(args);
92 }
93
94 /****************************************************************
95 ****************************************************************/
96
97 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
98                                            struct libnet_UnjoinCtx *r,
99                                            const char *format, ...)
100 {
101         va_list args;
102
103         if (r->out.error_string) {
104                 return;
105         }
106
107         va_start(args, format);
108         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
109         va_end(args);
110 }
111
112 #ifdef HAVE_ADS
113
114 /****************************************************************
115 ****************************************************************/
116
117 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
118                                      const char *netbios_domain_name,
119                                      const char *dc_name,
120                                      const char *user_name,
121                                      const char *password,
122                                      const char *ccname,
123                                      ADS_STRUCT **ads)
124 {
125         ADS_STATUS status;
126         ADS_STRUCT *my_ads = NULL;
127         char *cp;
128
129         my_ads = ads_init(dns_domain_name,
130                           netbios_domain_name,
131                           dc_name);
132         if (!my_ads) {
133                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
134         }
135
136         if (user_name) {
137                 SAFE_FREE(my_ads->auth.user_name);
138                 my_ads->auth.user_name = SMB_STRDUP(user_name);
139                 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
140                         *cp++ = '\0';
141                         SAFE_FREE(my_ads->auth.realm);
142                         my_ads->auth.realm = smb_xstrdup(cp);
143                         if (!strupper_m(my_ads->auth.realm)) {
144                                 ads_destroy(&my_ads);
145                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
146                         }
147                 }
148         }
149
150         if (password) {
151                 SAFE_FREE(my_ads->auth.password);
152                 my_ads->auth.password = SMB_STRDUP(password);
153         }
154
155         if (ccname != NULL) {
156                 SAFE_FREE(my_ads->auth.ccache_name);
157                 my_ads->auth.ccache_name = SMB_STRDUP(ccname);
158                 setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
159         }
160
161         status = ads_connect_user_creds(my_ads);
162         if (!ADS_ERR_OK(status)) {
163                 ads_destroy(&my_ads);
164                 return status;
165         }
166
167         *ads = my_ads;
168         return ADS_SUCCESS;
169 }
170
171 /****************************************************************
172 ****************************************************************/
173
174 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
175                                           struct libnet_JoinCtx *r,
176                                           bool use_machine_creds)
177 {
178         ADS_STATUS status;
179         const char *username;
180         const char *password;
181         const char *ccname = NULL;
182
183         if (use_machine_creds) {
184                 if (r->in.machine_name == NULL ||
185                     r->in.machine_password == NULL) {
186                         return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
187                 }
188                 username = talloc_strdup(mem_ctx, r->in.machine_name);
189                 if (username == NULL) {
190                         return ADS_ERROR(LDAP_NO_MEMORY);
191                 }
192                 if (username[strlen(username)] != '$') {
193                         username = talloc_asprintf(username, "%s$", username);
194                         if (username == NULL) {
195                                 return ADS_ERROR(LDAP_NO_MEMORY);
196                         }
197                 }
198                 password = r->in.machine_password;
199                 ccname = "MEMORY:libnet_join_machine_creds";
200         } else {
201                 username = r->in.admin_account;
202                 password = r->in.admin_password;
203
204                 /*
205                  * when r->in.use_kerberos is set to allow "net ads join -k" we
206                  * may not override the provided credential cache - gd
207                  */
208
209                 if (!r->in.use_kerberos) {
210                         ccname = "MEMORY:libnet_join_user_creds";
211                 }
212         }
213
214         status = libnet_connect_ads(r->out.dns_domain_name,
215                                     r->out.netbios_domain_name,
216                                     r->in.dc_name,
217                                     username,
218                                     password,
219                                     ccname,
220                                     &r->in.ads);
221         if (!ADS_ERR_OK(status)) {
222                 libnet_join_set_error_string(mem_ctx, r,
223                         "failed to connect to AD: %s",
224                         ads_errstr(status));
225                 return status;
226         }
227
228         if (!r->out.netbios_domain_name) {
229                 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
230                                                            r->in.ads->server.workgroup);
231                 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
232         }
233
234         if (!r->out.dns_domain_name) {
235                 r->out.dns_domain_name = talloc_strdup(mem_ctx,
236                                                        r->in.ads->config.realm);
237                 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
238         }
239
240         r->out.domain_is_ad = true;
241
242         return ADS_SUCCESS;
243 }
244
245 /****************************************************************
246 ****************************************************************/
247
248 static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
249                                                struct libnet_JoinCtx *r)
250 {
251         return libnet_join_connect_ads(mem_ctx, r, false);
252 }
253
254 /****************************************************************
255 ****************************************************************/
256
257 static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
258                                                   struct libnet_JoinCtx *r)
259 {
260         return libnet_join_connect_ads(mem_ctx, r, true);
261 }
262
263 /****************************************************************
264 ****************************************************************/
265
266 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
267                                             struct libnet_UnjoinCtx *r)
268 {
269         ADS_STATUS status;
270
271         status = libnet_connect_ads(r->in.domain_name,
272                                     r->in.domain_name,
273                                     r->in.dc_name,
274                                     r->in.admin_account,
275                                     r->in.admin_password,
276                                     NULL,
277                                     &r->in.ads);
278         if (!ADS_ERR_OK(status)) {
279                 libnet_unjoin_set_error_string(mem_ctx, r,
280                         "failed to connect to AD: %s",
281                         ads_errstr(status));
282         }
283
284         return status;
285 }
286
287 /****************************************************************
288  join a domain using ADS (LDAP mods)
289 ****************************************************************/
290
291 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
292                                                      struct libnet_JoinCtx *r)
293 {
294         ADS_STATUS status;
295         LDAPMessage *res = NULL;
296         const char *attrs[] = { "dn", NULL };
297         bool moved = false;
298
299         status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
300         if (!ADS_ERR_OK(status)) {
301                 return status;
302         }
303
304         status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
305         if (!ADS_ERR_OK(status)) {
306                 return status;
307         }
308
309         if (ads_count_replies(r->in.ads, res) != 1) {
310                 ads_msgfree(r->in.ads, res);
311                 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
312         }
313
314         ads_msgfree(r->in.ads, res);
315
316         /* Attempt to create the machine account and bail if this fails.
317            Assume that the admin wants exactly what they requested */
318
319         status = ads_create_machine_acct(r->in.ads,
320                                          r->in.machine_name,
321                                          r->in.account_ou,
322                                          r->in.desired_encryption_types);
323
324         if (ADS_ERR_OK(status)) {
325                 DEBUG(1,("machine account creation created\n"));
326                 return status;
327         } else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
328                     (status.err.rc == LDAP_ALREADY_EXISTS)) {
329                 status = ADS_SUCCESS;
330         }
331
332         if (!ADS_ERR_OK(status)) {
333                 DEBUG(1,("machine account creation failed\n"));
334                 return status;
335         }
336
337         status = ads_move_machine_acct(r->in.ads,
338                                        r->in.machine_name,
339                                        r->in.account_ou,
340                                        &moved);
341         if (!ADS_ERR_OK(status)) {
342                 DEBUG(1,("failure to locate/move pre-existing "
343                         "machine account\n"));
344                 return status;
345         }
346
347         DEBUG(1,("The machine account %s the specified OU.\n",
348                 moved ? "was moved into" : "already exists in"));
349
350         return status;
351 }
352
353 /****************************************************************
354 ****************************************************************/
355
356 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
357                                                     struct libnet_UnjoinCtx *r)
358 {
359         ADS_STATUS status;
360
361         if (!r->in.ads) {
362                 status = libnet_unjoin_connect_ads(mem_ctx, r);
363                 if (!ADS_ERR_OK(status)) {
364                         libnet_unjoin_set_error_string(mem_ctx, r,
365                                 "failed to connect to AD: %s",
366                                 ads_errstr(status));
367                         return status;
368                 }
369         }
370
371         status = ads_leave_realm(r->in.ads, r->in.machine_name);
372         if (!ADS_ERR_OK(status)) {
373                 libnet_unjoin_set_error_string(mem_ctx, r,
374                         "failed to leave realm: %s",
375                         ads_errstr(status));
376                 return status;
377         }
378
379         return ADS_SUCCESS;
380 }
381
382 /****************************************************************
383 ****************************************************************/
384
385 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
386                                                 struct libnet_JoinCtx *r)
387 {
388         ADS_STATUS status;
389         LDAPMessage *res = NULL;
390         char *dn = NULL;
391
392         if (!r->in.machine_name) {
393                 return ADS_ERROR(LDAP_NO_MEMORY);
394         }
395
396         status = ads_find_machine_acct(r->in.ads,
397                                        &res,
398                                        r->in.machine_name);
399         if (!ADS_ERR_OK(status)) {
400                 return status;
401         }
402
403         if (ads_count_replies(r->in.ads, res) != 1) {
404                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
405                 goto done;
406         }
407
408         dn = ads_get_dn(r->in.ads, mem_ctx, res);
409         if (!dn) {
410                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
411                 goto done;
412         }
413
414         r->out.dn = talloc_strdup(mem_ctx, dn);
415         if (!r->out.dn) {
416                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
417                 goto done;
418         }
419
420         if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
421                              &r->out.set_encryption_types)) {
422                 r->out.set_encryption_types = 0;
423         }
424
425  done:
426         ads_msgfree(r->in.ads, res);
427         TALLOC_FREE(dn);
428
429         return status;
430 }
431
432 static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
433                                                struct libnet_JoinCtx *r,
434                                                char ***spn_array,
435                                                size_t *num_spns)
436 {
437         ADS_STATUS status;
438
439         if (r->in.machine_name == NULL) {
440                 return ADS_ERROR_SYSTEM(EINVAL);
441         }
442
443         status = ads_get_service_principal_names(mem_ctx,
444                                                  r->in.ads,
445                                                  r->in.machine_name,
446                                                  spn_array,
447                                                  num_spns);
448
449         return status;
450 }
451
452 /****************************************************************
453  Set a machines dNSHostName and servicePrincipalName attributes
454 ****************************************************************/
455
456 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
457                                               struct libnet_JoinCtx *r)
458 {
459         ADS_STATUS status;
460         ADS_MODLIST mods;
461         fstring my_fqdn;
462         const char **spn_array = NULL;
463         size_t num_spns = 0;
464         char *spn = NULL;
465         bool ok;
466         const char **netbios_aliases = NULL;
467
468         /* Find our DN */
469
470         status = libnet_join_find_machine_acct(mem_ctx, r);
471         if (!ADS_ERR_OK(status)) {
472                 return status;
473         }
474
475         status = libnet_join_get_machine_spns(mem_ctx,
476                                               r,
477                                               discard_const_p(char **, &spn_array),
478                                               &num_spns);
479         if (!ADS_ERR_OK(status)) {
480                 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
481         }
482
483         /* Windows only creates HOST/shortname & HOST/fqdn. */
484
485         spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
486         if (!spn) {
487                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
488         }
489         if (!strupper_m(spn)) {
490                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
491         }
492
493         ok = ads_element_in_array(spn_array, num_spns, spn);
494         if (!ok) {
495                 ok = add_string_to_array(spn_array, spn,
496                                          &spn_array, &num_spns);
497                 if (!ok) {
498                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
499                 }
500         }
501
502         if (!name_to_fqdn(my_fqdn, r->in.machine_name)
503             || (strchr(my_fqdn, '.') == NULL)) {
504                 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
505                              r->out.dns_domain_name);
506         }
507
508         if (!strlower_m(my_fqdn)) {
509                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
510         }
511
512         if (!strequal(my_fqdn, r->in.machine_name)) {
513                 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
514                 if (!spn) {
515                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
516                 }
517
518                 ok = ads_element_in_array(spn_array, num_spns, spn);
519                 if (!ok) {
520                         ok = add_string_to_array(spn_array, spn,
521                                                  &spn_array, &num_spns);
522                         if (!ok) {
523                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
524                         }
525                 }
526         }
527
528         netbios_aliases = lp_netbios_aliases();
529         if (netbios_aliases != NULL) {
530                 for (; *netbios_aliases != NULL; netbios_aliases++) {
531                         /*
532                          * Add HOST/NETBIOSNAME
533                          */
534                         spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases);
535                         if (spn == NULL) {
536                                 TALLOC_FREE(spn);
537                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
538                         }
539                         if (!strupper_m(spn)) {
540                                 TALLOC_FREE(spn);
541                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
542                         }
543
544                         ok = ads_element_in_array(spn_array, num_spns, spn);
545                         if (ok) {
546                                 TALLOC_FREE(spn);
547                                 continue;
548                         }
549                         ok = add_string_to_array(spn_array, spn,
550                                                  &spn_array, &num_spns);
551                         if (!ok) {
552                                 TALLOC_FREE(spn);
553                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
554                         }
555                         TALLOC_FREE(spn);
556
557                         /*
558                          * Add HOST/netbiosname.domainname
559                          */
560                         if (r->out.dns_domain_name == NULL) {
561                                 continue;
562                         }
563                         fstr_sprintf(my_fqdn, "%s.%s",
564                                      *netbios_aliases,
565                                      r->out.dns_domain_name);
566
567                         spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
568                         if (spn == NULL) {
569                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
570                         }
571
572                         ok = ads_element_in_array(spn_array, num_spns, spn);
573                         if (ok) {
574                                 TALLOC_FREE(spn);
575                                 continue;
576                         }
577                         ok = add_string_to_array(spn_array, spn,
578                                                  &spn_array, &num_spns);
579                         if (!ok) {
580                                 TALLOC_FREE(spn);
581                                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
582                         }
583                         TALLOC_FREE(spn);
584                 }
585         }
586
587         /* make sure to NULL terminate the array */
588         spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
589         if (spn_array == NULL) {
590                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
591         }
592         spn_array[num_spns] = NULL;
593
594         mods = ads_init_mods(mem_ctx);
595         if (!mods) {
596                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
597         }
598
599         /* fields of primary importance */
600
601         status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
602         if (!ADS_ERR_OK(status)) {
603                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
604         }
605
606         status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
607                                  spn_array);
608         if (!ADS_ERR_OK(status)) {
609                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
610         }
611
612         return ads_gen_mod(r->in.ads, r->out.dn, mods);
613 }
614
615 /****************************************************************
616 ****************************************************************/
617
618 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
619                                               struct libnet_JoinCtx *r)
620 {
621         ADS_STATUS status;
622         ADS_MODLIST mods;
623
624         if (!r->in.create_upn) {
625                 return ADS_SUCCESS;
626         }
627
628         /* Find our DN */
629
630         status = libnet_join_find_machine_acct(mem_ctx, r);
631         if (!ADS_ERR_OK(status)) {
632                 return status;
633         }
634
635         if (!r->in.upn) {
636                 const char *realm = r->out.dns_domain_name;
637
638                 /* in case we are about to generate a keytab during the join
639                  * make sure the default upn we create is usable with kinit -k.
640                  * gd */
641
642                 if (USE_KERBEROS_KEYTAB) {
643                         realm = talloc_strdup_upper(mem_ctx,
644                                                     r->out.dns_domain_name);
645                 }
646
647                 if (!realm) {
648                         return ADS_ERROR(LDAP_NO_MEMORY);
649                 }
650
651                 r->in.upn = talloc_asprintf(mem_ctx,
652                                             "host/%s@%s",
653                                             r->in.machine_name,
654                                             realm);
655                 if (!r->in.upn) {
656                         return ADS_ERROR(LDAP_NO_MEMORY);
657                 }
658         }
659
660         /* now do the mods */
661
662         mods = ads_init_mods(mem_ctx);
663         if (!mods) {
664                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
665         }
666
667         /* fields of primary importance */
668
669         status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
670         if (!ADS_ERR_OK(status)) {
671                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
672         }
673
674         return ads_gen_mod(r->in.ads, r->out.dn, mods);
675 }
676
677
678 /****************************************************************
679 ****************************************************************/
680
681 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
682                                                 struct libnet_JoinCtx *r)
683 {
684         ADS_STATUS status;
685         ADS_MODLIST mods;
686         char *os_sp = NULL;
687
688         if (!r->in.os_name || !r->in.os_version ) {
689                 return ADS_SUCCESS;
690         }
691
692         /* Find our DN */
693
694         status = libnet_join_find_machine_acct(mem_ctx, r);
695         if (!ADS_ERR_OK(status)) {
696                 return status;
697         }
698
699         /* now do the mods */
700
701         mods = ads_init_mods(mem_ctx);
702         if (!mods) {
703                 return ADS_ERROR(LDAP_NO_MEMORY);
704         }
705
706         if (r->in.os_servicepack) {
707                 /*
708                  * if blank string then leave os_sp equal to NULL to force
709                  * attribute delete (LDAP_MOD_DELETE)
710                  */
711                 if (!strequal(r->in.os_servicepack,"")) {
712                         os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
713                 }
714         } else {
715                 os_sp = talloc_asprintf(mem_ctx, "Samba %s",
716                                         samba_version_string());
717         }
718         if (!os_sp && !strequal(r->in.os_servicepack,"")) {
719                 return ADS_ERROR(LDAP_NO_MEMORY);
720         }
721
722         /* fields of primary importance */
723
724         status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
725                              r->in.os_name);
726         if (!ADS_ERR_OK(status)) {
727                 return status;
728         }
729
730         status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
731                              r->in.os_version);
732         if (!ADS_ERR_OK(status)) {
733                 return status;
734         }
735
736         status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
737                              os_sp);
738         if (!ADS_ERR_OK(status)) {
739                 return status;
740         }
741
742         return ads_gen_mod(r->in.ads, r->out.dn, mods);
743 }
744
745 /****************************************************************
746 ****************************************************************/
747
748 static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
749                                          struct libnet_JoinCtx *r)
750 {
751         ADS_STATUS status;
752         ADS_MODLIST mods;
753         const char *etype_list_str;
754
755         etype_list_str = talloc_asprintf(mem_ctx, "%d",
756                                          r->in.desired_encryption_types);
757         if (!etype_list_str) {
758                 return ADS_ERROR(LDAP_NO_MEMORY);
759         }
760
761         /* Find our DN */
762
763         status = libnet_join_find_machine_acct(mem_ctx, r);
764         if (!ADS_ERR_OK(status)) {
765                 return status;
766         }
767
768         if (r->in.desired_encryption_types == r->out.set_encryption_types) {
769                 return ADS_SUCCESS;
770         }
771
772         /* now do the mods */
773
774         mods = ads_init_mods(mem_ctx);
775         if (!mods) {
776                 return ADS_ERROR(LDAP_NO_MEMORY);
777         }
778
779         status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
780                              etype_list_str);
781         if (!ADS_ERR_OK(status)) {
782                 return status;
783         }
784
785         status = ads_gen_mod(r->in.ads, r->out.dn, mods);
786         if (!ADS_ERR_OK(status)) {
787                 return status;
788         }
789
790         r->out.set_encryption_types = r->in.desired_encryption_types;
791
792         return ADS_SUCCESS;
793 }
794
795 /****************************************************************
796 ****************************************************************/
797
798 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
799                                       struct libnet_JoinCtx *r)
800 {
801         if (!USE_SYSTEM_KEYTAB) {
802                 return true;
803         }
804
805         if (ads_keytab_create_default(r->in.ads) != 0) {
806                 return false;
807         }
808
809         return true;
810 }
811
812 /****************************************************************
813 ****************************************************************/
814
815 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
816                                                  struct libnet_JoinCtx *r)
817 {
818         uint32_t domain_func;
819         ADS_STATUS status;
820         const char *salt = NULL;
821         char *std_salt = NULL;
822
823         status = ads_domain_func_level(r->in.ads, &domain_func);
824         if (!ADS_ERR_OK(status)) {
825                 libnet_join_set_error_string(mem_ctx, r,
826                         "failed to determine domain functional level: %s",
827                         ads_errstr(status));
828                 return false;
829         }
830
831         /* go ahead and setup the default salt */
832
833         std_salt = kerberos_standard_des_salt();
834         if (!std_salt) {
835                 libnet_join_set_error_string(mem_ctx, r,
836                         "failed to obtain standard DES salt");
837                 return false;
838         }
839
840         salt = talloc_strdup(mem_ctx, std_salt);
841         if (!salt) {
842                 return false;
843         }
844
845         SAFE_FREE(std_salt);
846
847         /* if it's a Windows functional domain, we have to look for the UPN */
848
849         if (domain_func == DS_DOMAIN_FUNCTION_2000) {
850                 char *upn;
851
852                 upn = ads_get_upn(r->in.ads, mem_ctx,
853                                   r->in.machine_name);
854                 if (upn) {
855                         salt = talloc_strdup(mem_ctx, upn);
856                         if (!salt) {
857                                 return false;
858                         }
859                 }
860         }
861
862         return kerberos_secrets_store_des_salt(salt);
863 }
864
865 /****************************************************************
866 ****************************************************************/
867
868 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
869                                                   struct libnet_JoinCtx *r)
870 {
871         ADS_STATUS status;
872         bool need_etype_update = false;
873
874         if (!r->in.ads) {
875                 status = libnet_join_connect_ads_user(mem_ctx, r);
876                 if (!ADS_ERR_OK(status)) {
877                         return status;
878                 }
879         }
880
881         status = libnet_join_set_machine_spn(mem_ctx, r);
882         if (!ADS_ERR_OK(status)) {
883                 libnet_join_set_error_string(mem_ctx, r,
884                         "Failed to set machine spn: %s\n"
885                         "Do you have sufficient permissions to create machine "
886                         "accounts?",
887                         ads_errstr(status));
888                 return status;
889         }
890
891         status = libnet_join_set_os_attributes(mem_ctx, r);
892         if (!ADS_ERR_OK(status)) {
893                 libnet_join_set_error_string(mem_ctx, r,
894                         "failed to set machine os attributes: %s",
895                         ads_errstr(status));
896                 return status;
897         }
898
899         status = libnet_join_set_machine_upn(mem_ctx, r);
900         if (!ADS_ERR_OK(status)) {
901                 libnet_join_set_error_string(mem_ctx, r,
902                         "failed to set machine upn: %s",
903                         ads_errstr(status));
904                 return status;
905         }
906
907         status = libnet_join_find_machine_acct(mem_ctx, r);
908         if (!ADS_ERR_OK(status)) {
909                 return status;
910         }
911
912         if (r->in.desired_encryption_types != r->out.set_encryption_types) {
913                 uint32_t func_level = 0;
914
915                 status = ads_domain_func_level(r->in.ads, &func_level);
916                 if (!ADS_ERR_OK(status)) {
917                         libnet_join_set_error_string(mem_ctx, r,
918                                 "failed to query domain controller functional level: %s",
919                                 ads_errstr(status));
920                         return status;
921                 }
922
923                 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
924                         need_etype_update = true;
925                 }
926         }
927
928         if (need_etype_update) {
929                 /*
930                  * We need to reconnect as machine account in order
931                  * to update msDS-SupportedEncryptionTypes reliable
932                  */
933
934                 if (r->in.ads->auth.ccache_name != NULL) {
935                         ads_kdestroy(r->in.ads->auth.ccache_name);
936                 }
937
938                 ads_destroy(&r->in.ads);
939
940                 status = libnet_join_connect_ads_machine(mem_ctx, r);
941                 if (!ADS_ERR_OK(status)) {
942                         libnet_join_set_error_string(mem_ctx, r,
943                                 "Failed to connect as machine account: %s",
944                                 ads_errstr(status));
945                         return status;
946                 }
947
948                 status = libnet_join_set_etypes(mem_ctx, r);
949                 if (!ADS_ERR_OK(status)) {
950                         libnet_join_set_error_string(mem_ctx, r,
951                                 "failed to set machine kerberos encryption types: %s",
952                                 ads_errstr(status));
953                         return status;
954                 }
955         }
956
957         if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
958                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
959         }
960
961         if (!libnet_join_create_keytab(mem_ctx, r)) {
962                 libnet_join_set_error_string(mem_ctx, r,
963                         "failed to create kerberos keytab");
964                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
965         }
966
967         return ADS_SUCCESS;
968 }
969 #endif /* HAVE_ADS */
970
971 /****************************************************************
972  Store the machine password and domain SID
973 ****************************************************************/
974
975 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
976                                                  struct libnet_JoinCtx *r)
977 {
978         if (!secrets_store_domain_sid(r->out.netbios_domain_name,
979                                       r->out.domain_sid))
980         {
981                 DEBUG(1,("Failed to save domain sid\n"));
982                 return false;
983         }
984
985         if (!secrets_store_machine_password(r->in.machine_password,
986                                             r->out.netbios_domain_name,
987                                             r->in.secure_channel_type))
988         {
989                 DEBUG(1,("Failed to save machine password\n"));
990                 return false;
991         }
992
993         return true;
994 }
995
996 /****************************************************************
997  Connect dc's IPC$ share
998 ****************************************************************/
999
1000 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
1001                                            const char *user,
1002                                            const char *domain,
1003                                            const char *pass,
1004                                            bool use_kerberos,
1005                                            struct cli_state **cli)
1006 {
1007         int flags = 0;
1008
1009         if (use_kerberos) {
1010                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1011         }
1012
1013         if (use_kerberos && pass) {
1014                 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
1015         }
1016
1017         return cli_full_connection(cli, NULL,
1018                                    dc,
1019                                    NULL, 0,
1020                                    "IPC$", "IPC",
1021                                    user,
1022                                    domain,
1023                                    pass,
1024                                    flags,
1025                                    SMB_SIGNING_IPC_DEFAULT);
1026 }
1027
1028 /****************************************************************
1029  Lookup domain dc's info
1030 ****************************************************************/
1031
1032 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1033                                           struct libnet_JoinCtx *r,
1034                                           struct cli_state **cli)
1035 {
1036         struct rpc_pipe_client *pipe_hnd = NULL;
1037         struct policy_handle lsa_pol;
1038         NTSTATUS status, result;
1039         union lsa_PolicyInformation *info = NULL;
1040         struct dcerpc_binding_handle *b;
1041
1042         status = libnet_join_connect_dc_ipc(r->in.dc_name,
1043                                             r->in.admin_account,
1044                                             r->in.admin_domain,
1045                                             r->in.admin_password,
1046                                             r->in.use_kerberos,
1047                                             cli);
1048         if (!NT_STATUS_IS_OK(status)) {
1049                 goto done;
1050         }
1051
1052         status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1053                                           &pipe_hnd);
1054         if (!NT_STATUS_IS_OK(status)) {
1055                 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1056                         nt_errstr(status)));
1057                 goto done;
1058         }
1059
1060         b = pipe_hnd->binding_handle;
1061
1062         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1063                                         SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1064         if (!NT_STATUS_IS_OK(status)) {
1065                 goto done;
1066         }
1067
1068         status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1069                                              &lsa_pol,
1070                                              LSA_POLICY_INFO_DNS,
1071                                              &info,
1072                                              &result);
1073         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1074                 r->out.domain_is_ad = true;
1075                 r->out.netbios_domain_name = info->dns.name.string;
1076                 r->out.dns_domain_name = info->dns.dns_domain.string;
1077                 r->out.forest_name = info->dns.dns_forest.string;
1078                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1079                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1080         }
1081
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1084                                                     &lsa_pol,
1085                                                     LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1086                                                     &info,
1087                                                     &result);
1088                 if (!NT_STATUS_IS_OK(status)) {
1089                         goto done;
1090                 }
1091                 if (!NT_STATUS_IS_OK(result)) {
1092                         status = result;
1093                         goto done;
1094                 }
1095
1096                 r->out.netbios_domain_name = info->account_domain.name.string;
1097                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1098                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1099         }
1100
1101         dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1102         TALLOC_FREE(pipe_hnd);
1103
1104  done:
1105         return status;
1106 }
1107
1108 /****************************************************************
1109  Do the domain join unsecure
1110 ****************************************************************/
1111
1112 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1113                                                     struct libnet_JoinCtx *r,
1114                                                     struct cli_state *cli)
1115 {
1116         TALLOC_CTX *frame = talloc_stackframe();
1117         struct rpc_pipe_client *netlogon_pipe = NULL;
1118         struct netlogon_creds_cli_context *netlogon_creds = NULL;
1119         struct samr_Password current_nt_hash;
1120         const char *account_name = NULL;
1121         NTSTATUS status;
1122
1123         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1124                                           &netlogon_pipe);
1125         if (!NT_STATUS_IS_OK(status)) {
1126                 TALLOC_FREE(frame);
1127                 return status;
1128         }
1129
1130         if (!r->in.machine_password) {
1131                 r->in.machine_password = generate_random_password(mem_ctx,
1132                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
1133                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1134                 if (r->in.machine_password == NULL) {
1135                         TALLOC_FREE(frame);
1136                         return NT_STATUS_NO_MEMORY;
1137                 }
1138         }
1139
1140         /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1141         E_md4hash(r->in.admin_password, current_nt_hash.hash);
1142
1143         account_name = talloc_asprintf(frame, "%s$",
1144                                        r->in.machine_name);
1145         if (account_name == NULL) {
1146                 TALLOC_FREE(frame);
1147                 return NT_STATUS_NO_MEMORY;
1148         }
1149
1150         status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
1151                                               r->in.domain_name,
1152                                               account_name,
1153                                               r->in.secure_channel_type,
1154                                               r->in.msg_ctx,
1155                                               frame,
1156                                               &netlogon_creds);
1157         if (!NT_STATUS_IS_OK(status)) {
1158                 TALLOC_FREE(frame);
1159                 return status;
1160         }
1161
1162         status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1163                                              netlogon_creds,
1164                                              true, /* force_reauth */
1165                                              current_nt_hash,
1166                                              NULL); /* previous_nt_hash */
1167         if (!NT_STATUS_IS_OK(status)) {
1168                 TALLOC_FREE(frame);
1169                 return status;
1170         }
1171
1172         status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1173                                                       netlogon_pipe->binding_handle,
1174                                                       r->in.machine_password,
1175                                                       NULL); /* new_version */
1176         if (!NT_STATUS_IS_OK(status)) {
1177                 TALLOC_FREE(frame);
1178                 return status;
1179         }
1180
1181         TALLOC_FREE(frame);
1182         return NT_STATUS_OK;
1183 }
1184
1185 /****************************************************************
1186  Do the domain join
1187 ****************************************************************/
1188
1189 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1190                                            struct libnet_JoinCtx *r,
1191                                            struct cli_state *cli)
1192 {
1193         struct rpc_pipe_client *pipe_hnd = NULL;
1194         struct policy_handle sam_pol, domain_pol, user_pol;
1195         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1196         char *acct_name;
1197         struct lsa_String lsa_acct_name;
1198         uint32_t user_rid;
1199         uint32_t acct_flags = ACB_WSTRUST;
1200         struct samr_Ids user_rids;
1201         struct samr_Ids name_types;
1202         union samr_UserInfo user_info;
1203         struct dcerpc_binding_handle *b = NULL;
1204         unsigned int old_timeout = 0;
1205
1206         DATA_BLOB session_key = data_blob_null;
1207         struct samr_CryptPassword crypt_pwd;
1208         struct samr_CryptPasswordEx crypt_pwd_ex;
1209
1210         ZERO_STRUCT(sam_pol);
1211         ZERO_STRUCT(domain_pol);
1212         ZERO_STRUCT(user_pol);
1213
1214         switch (r->in.secure_channel_type) {
1215         case SEC_CHAN_WKSTA:
1216                 acct_flags = ACB_WSTRUST;
1217                 break;
1218         case SEC_CHAN_BDC:
1219                 acct_flags = ACB_SVRTRUST;
1220                 break;
1221         default:
1222                 return NT_STATUS_INVALID_PARAMETER;
1223         }
1224
1225         if (!r->in.machine_password) {
1226                 r->in.machine_password = generate_random_password(mem_ctx,
1227                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
1228                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1229                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1230         }
1231
1232         /* Open the domain */
1233
1234         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1235                                           &pipe_hnd);
1236         if (!NT_STATUS_IS_OK(status)) {
1237                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1238                         nt_errstr(status)));
1239                 goto done;
1240         }
1241
1242         b = pipe_hnd->binding_handle;
1243
1244         status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1245         if (!NT_STATUS_IS_OK(status)) {
1246                 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1247                         nt_errstr(status)));
1248                 goto done;
1249         }
1250
1251         status = dcerpc_samr_Connect2(b, mem_ctx,
1252                                       pipe_hnd->desthost,
1253                                       SAMR_ACCESS_ENUM_DOMAINS
1254                                       | SAMR_ACCESS_LOOKUP_DOMAIN,
1255                                       &sam_pol,
1256                                       &result);
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 goto done;
1259         }
1260         if (!NT_STATUS_IS_OK(result)) {
1261                 status = result;
1262                 goto done;
1263         }
1264
1265         status = dcerpc_samr_OpenDomain(b, mem_ctx,
1266                                         &sam_pol,
1267                                         SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1268                                         | SAMR_DOMAIN_ACCESS_CREATE_USER
1269                                         | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1270                                         r->out.domain_sid,
1271                                         &domain_pol,
1272                                         &result);
1273         if (!NT_STATUS_IS_OK(status)) {
1274                 goto done;
1275         }
1276         if (!NT_STATUS_IS_OK(result)) {
1277                 status = result;
1278                 goto done;
1279         }
1280
1281         /* Create domain user */
1282
1283         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1284         if (!strlower_m(acct_name)) {
1285                 status = NT_STATUS_INVALID_PARAMETER;
1286                 goto done;
1287         }
1288
1289         init_lsa_String(&lsa_acct_name, acct_name);
1290
1291         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1292                 uint32_t access_desired =
1293                         SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1294                         SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1295                         SAMR_USER_ACCESS_SET_PASSWORD |
1296                         SAMR_USER_ACCESS_GET_ATTRIBUTES |
1297                         SAMR_USER_ACCESS_SET_ATTRIBUTES;
1298                 uint32_t access_granted = 0;
1299
1300                 DEBUG(10,("Creating account with desired access mask: %d\n",
1301                         access_desired));
1302
1303                 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1304                                                  &domain_pol,
1305                                                  &lsa_acct_name,
1306                                                  acct_flags,
1307                                                  access_desired,
1308                                                  &user_pol,
1309                                                  &access_granted,
1310                                                  &user_rid,
1311                                                  &result);
1312                 if (!NT_STATUS_IS_OK(status)) {
1313                         goto done;
1314                 }
1315
1316                 status = result;
1317                 if (!NT_STATUS_IS_OK(status) &&
1318                     !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1319
1320                         DEBUG(10,("Creation of workstation account failed: %s\n",
1321                                 nt_errstr(status)));
1322
1323                         /* If NT_STATUS_ACCESS_DENIED then we have a valid
1324                            username/password combo but the user does not have
1325                            administrator access. */
1326
1327                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1328                                 libnet_join_set_error_string(mem_ctx, r,
1329                                         "User specified does not have "
1330                                         "administrator privileges");
1331                         }
1332
1333                         goto done;
1334                 }
1335
1336                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1337                         if (!(r->in.join_flags &
1338                               WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1339                                 goto done;
1340                         }
1341                 }
1342
1343                 /* We *must* do this.... don't ask... */
1344
1345                 if (NT_STATUS_IS_OK(status)) {
1346                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1347                 }
1348         }
1349
1350         status = dcerpc_samr_LookupNames(b, mem_ctx,
1351                                          &domain_pol,
1352                                          1,
1353                                          &lsa_acct_name,
1354                                          &user_rids,
1355                                          &name_types,
1356                                          &result);
1357         if (!NT_STATUS_IS_OK(status)) {
1358                 goto done;
1359         }
1360         if (!NT_STATUS_IS_OK(result)) {
1361                 status = result;
1362                 goto done;
1363         }
1364         if (user_rids.count != 1) {
1365                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1366                 goto done;
1367         }
1368         if (name_types.count != 1) {
1369                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1370                 goto done;
1371         }
1372
1373         if (name_types.ids[0] != SID_NAME_USER) {
1374                 DEBUG(0,("%s is not a user account (type=%d)\n",
1375                         acct_name, name_types.ids[0]));
1376                 status = NT_STATUS_INVALID_WORKSTATION;
1377                 goto done;
1378         }
1379
1380         user_rid = user_rids.ids[0];
1381
1382         /* Open handle on user */
1383
1384         status = dcerpc_samr_OpenUser(b, mem_ctx,
1385                                       &domain_pol,
1386                                       SEC_FLAG_MAXIMUM_ALLOWED,
1387                                       user_rid,
1388                                       &user_pol,
1389                                       &result);
1390         if (!NT_STATUS_IS_OK(status)) {
1391                 goto done;
1392         }
1393         if (!NT_STATUS_IS_OK(result)) {
1394                 status = result;
1395                 goto done;
1396         }
1397
1398         /* Fill in the additional account flags now */
1399
1400         acct_flags |= ACB_PWNOEXP;
1401
1402         /* Set account flags on machine account */
1403         ZERO_STRUCT(user_info.info16);
1404         user_info.info16.acct_flags = acct_flags;
1405
1406         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1407                                          &user_pol,
1408                                          16,
1409                                          &user_info,
1410                                          &result);
1411         if (!NT_STATUS_IS_OK(status)) {
1412                 dcerpc_samr_DeleteUser(b, mem_ctx,
1413                                        &user_pol,
1414                                        &result);
1415
1416                 libnet_join_set_error_string(mem_ctx, r,
1417                         "Failed to set account flags for machine account (%s)\n",
1418                         nt_errstr(status));
1419                 goto done;
1420         }
1421
1422         if (!NT_STATUS_IS_OK(result)) {
1423                 status = result;
1424
1425                 dcerpc_samr_DeleteUser(b, mem_ctx,
1426                                        &user_pol,
1427                                        &result);
1428
1429                 libnet_join_set_error_string(mem_ctx, r,
1430                         "Failed to set account flags for machine account (%s)\n",
1431                         nt_errstr(status));
1432                 goto done;
1433         }
1434
1435         /* Set password on machine account - first try level 26 */
1436
1437         /*
1438          * increase the timeout as password filter modules on the DC
1439          * might delay the operation for a significant amount of time
1440          */
1441         old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1442
1443         init_samr_CryptPasswordEx(r->in.machine_password,
1444                                   &session_key,
1445                                   &crypt_pwd_ex);
1446
1447         user_info.info26.password = crypt_pwd_ex;
1448         user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1449
1450         status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1451                                           &user_pol,
1452                                           26,
1453                                           &user_info,
1454                                           &result);
1455
1456         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1457
1458                 /* retry with level 24 */
1459
1460                 init_samr_CryptPassword(r->in.machine_password,
1461                                         &session_key,
1462                                         &crypt_pwd);
1463
1464                 user_info.info24.password = crypt_pwd;
1465                 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1466
1467                 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1468                                                   &user_pol,
1469                                                   24,
1470                                                   &user_info,
1471                                                   &result);
1472         }
1473
1474         old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1475
1476         if (!NT_STATUS_IS_OK(status)) {
1477
1478                 dcerpc_samr_DeleteUser(b, mem_ctx,
1479                                        &user_pol,
1480                                        &result);
1481
1482                 libnet_join_set_error_string(mem_ctx, r,
1483                         "Failed to set password for machine account (%s)\n",
1484                         nt_errstr(status));
1485                 goto done;
1486         }
1487         if (!NT_STATUS_IS_OK(result)) {
1488                 status = result;
1489
1490                 dcerpc_samr_DeleteUser(b, mem_ctx,
1491                                        &user_pol,
1492                                        &result);
1493
1494                 libnet_join_set_error_string(mem_ctx, r,
1495                         "Failed to set password for machine account (%s)\n",
1496                         nt_errstr(status));
1497                 goto done;
1498         }
1499
1500         status = NT_STATUS_OK;
1501
1502  done:
1503         if (!pipe_hnd) {
1504                 return status;
1505         }
1506
1507         data_blob_clear_free(&session_key);
1508
1509         if (is_valid_policy_hnd(&sam_pol)) {
1510                 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1511         }
1512         if (is_valid_policy_hnd(&domain_pol)) {
1513                 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1514         }
1515         if (is_valid_policy_hnd(&user_pol)) {
1516                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1517         }
1518         TALLOC_FREE(pipe_hnd);
1519
1520         return status;
1521 }
1522
1523 /****************************************************************
1524 ****************************************************************/
1525
1526 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1527                         const char *netbios_domain_name,
1528                         const char *dc_name,
1529                         const bool use_kerberos)
1530 {
1531         TALLOC_CTX *frame = talloc_stackframe();
1532         struct cli_state *cli = NULL;
1533         struct rpc_pipe_client *netlogon_pipe = NULL;
1534         struct cli_credentials *cli_creds = NULL;
1535         struct netlogon_creds_cli_context *netlogon_creds = NULL;
1536         struct netlogon_creds_CredentialState *creds = NULL;
1537         uint32_t netlogon_flags = 0;
1538         NTSTATUS status;
1539         const char *machine_account = NULL;
1540         const char *machine_domain = NULL;
1541         const char *machine_password = NULL;
1542         int flags = 0;
1543
1544         if (!dc_name) {
1545                 TALLOC_FREE(frame);
1546                 return NT_STATUS_INVALID_PARAMETER;
1547         }
1548
1549         if (!secrets_init()) {
1550                 TALLOC_FREE(frame);
1551                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1552         }
1553
1554         status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1555                                            frame, &cli_creds);
1556         if (!NT_STATUS_IS_OK(status)) {
1557                 TALLOC_FREE(frame);
1558                 return status;
1559         }
1560
1561         /* we don't want any old password */
1562         cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1563
1564         if (use_kerberos) {
1565                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1566         }
1567
1568         machine_account = cli_credentials_get_username(cli_creds);
1569         machine_domain = cli_credentials_get_domain(cli_creds);
1570         machine_password = cli_credentials_get_password(cli_creds);
1571
1572         status = cli_full_connection(&cli, NULL,
1573                                      dc_name,
1574                                      NULL, 0,
1575                                      "IPC$", "IPC",
1576                                      machine_account,
1577                                      machine_domain,
1578                                      machine_password,
1579                                      flags,
1580                                      SMB_SIGNING_IPC_DEFAULT);
1581
1582         if (!NT_STATUS_IS_OK(status)) {
1583                 status = cli_full_connection(&cli, NULL,
1584                                              dc_name,
1585                                              NULL, 0,
1586                                              "IPC$", "IPC",
1587                                              "",
1588                                              NULL,
1589                                              "",
1590                                              0,
1591                                              SMB_SIGNING_IPC_DEFAULT);
1592         }
1593
1594         if (!NT_STATUS_IS_OK(status)) {
1595                 TALLOC_FREE(frame);
1596                 return status;
1597         }
1598
1599         status = rpccli_create_netlogon_creds_with_creds(cli_creds,
1600                                                          dc_name,
1601                                                          msg_ctx,
1602                                                          frame,
1603                                                          &netlogon_creds);
1604         if (!NT_STATUS_IS_OK(status)) {
1605                 cli_shutdown(cli);
1606                 TALLOC_FREE(frame);
1607                 return status;
1608         }
1609
1610         status = rpccli_setup_netlogon_creds_with_creds(cli, NCACN_NP,
1611                                                         netlogon_creds,
1612                                                         true, /* force_reauth */
1613                                                         cli_creds);
1614         if (!NT_STATUS_IS_OK(status)) {
1615                 DEBUG(0,("connect_to_domain_password_server: "
1616                          "unable to open the domain client session to "
1617                          "machine %s. Flags[0x%08X] Error was : %s.\n",
1618                          dc_name, (unsigned)netlogon_flags,
1619                          nt_errstr(status)));
1620                 cli_shutdown(cli);
1621                 TALLOC_FREE(frame);
1622                 return status;
1623         }
1624
1625         status = netlogon_creds_cli_get(netlogon_creds,
1626                                         talloc_tos(),
1627                                         &creds);
1628         if (!NT_STATUS_IS_OK(status)) {
1629                 cli_shutdown(cli);
1630                 TALLOC_FREE(frame);
1631                 return status;
1632         }
1633         netlogon_flags = creds->negotiate_flags;
1634         TALLOC_FREE(creds);
1635
1636         if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1637                 cli_shutdown(cli);
1638                 TALLOC_FREE(frame);
1639                 return NT_STATUS_OK;
1640         }
1641
1642         status = cli_rpc_pipe_open_schannel_with_creds(
1643                 cli, &ndr_table_netlogon, NCACN_NP,
1644                 cli_creds,
1645                 netlogon_creds, &netlogon_pipe);
1646
1647         TALLOC_FREE(netlogon_pipe);
1648
1649         if (!NT_STATUS_IS_OK(status)) {
1650                 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1651                         "on netlogon pipe to server %s for domain %s. "
1652                         "Error was %s\n",
1653                         smbXcli_conn_remote_name(cli->conn),
1654                         netbios_domain_name, nt_errstr(status)));
1655                 cli_shutdown(cli);
1656                 TALLOC_FREE(frame);
1657                 return status;
1658         }
1659
1660         cli_shutdown(cli);
1661         TALLOC_FREE(frame);
1662         return NT_STATUS_OK;
1663 }
1664
1665 /****************************************************************
1666 ****************************************************************/
1667
1668 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1669                                       struct libnet_JoinCtx *r)
1670 {
1671         NTSTATUS status;
1672
1673         status = libnet_join_ok(r->in.msg_ctx,
1674                                 r->out.netbios_domain_name,
1675                                 r->in.dc_name,
1676                                 r->in.use_kerberos);
1677         if (!NT_STATUS_IS_OK(status)) {
1678                 libnet_join_set_error_string(mem_ctx, r,
1679                         "failed to verify domain membership after joining: %s",
1680                         get_friendly_nt_error_msg(status));
1681                 return WERR_SETUP_NOT_JOINED;
1682         }
1683
1684         return WERR_OK;
1685 }
1686
1687 /****************************************************************
1688 ****************************************************************/
1689
1690 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1691                                                     struct libnet_UnjoinCtx *r)
1692 {
1693         if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1694                 return false;
1695         }
1696
1697         if (!secrets_delete_domain_sid(lp_workgroup())) {
1698                 return false;
1699         }
1700
1701         return true;
1702 }
1703
1704 /****************************************************************
1705 ****************************************************************/
1706
1707 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1708                                              struct libnet_UnjoinCtx *r)
1709 {
1710         struct cli_state *cli = NULL;
1711         struct rpc_pipe_client *pipe_hnd = NULL;
1712         struct policy_handle sam_pol, domain_pol, user_pol;
1713         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1714         char *acct_name;
1715         uint32_t user_rid;
1716         struct lsa_String lsa_acct_name;
1717         struct samr_Ids user_rids;
1718         struct samr_Ids name_types;
1719         union samr_UserInfo *info = NULL;
1720         struct dcerpc_binding_handle *b = NULL;
1721
1722         ZERO_STRUCT(sam_pol);
1723         ZERO_STRUCT(domain_pol);
1724         ZERO_STRUCT(user_pol);
1725
1726         status = libnet_join_connect_dc_ipc(r->in.dc_name,
1727                                             r->in.admin_account,
1728                                             r->in.admin_domain,
1729                                             r->in.admin_password,
1730                                             r->in.use_kerberos,
1731                                             &cli);
1732         if (!NT_STATUS_IS_OK(status)) {
1733                 goto done;
1734         }
1735
1736         /* Open the domain */
1737
1738         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1739                                           &pipe_hnd);
1740         if (!NT_STATUS_IS_OK(status)) {
1741                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1742                         nt_errstr(status)));
1743                 goto done;
1744         }
1745
1746         b = pipe_hnd->binding_handle;
1747
1748         status = dcerpc_samr_Connect2(b, mem_ctx,
1749                                       pipe_hnd->desthost,
1750                                       SEC_FLAG_MAXIMUM_ALLOWED,
1751                                       &sam_pol,
1752                                       &result);
1753         if (!NT_STATUS_IS_OK(status)) {
1754                 goto done;
1755         }
1756         if (!NT_STATUS_IS_OK(result)) {
1757                 status = result;
1758                 goto done;
1759         }
1760
1761         status = dcerpc_samr_OpenDomain(b, mem_ctx,
1762                                         &sam_pol,
1763                                         SEC_FLAG_MAXIMUM_ALLOWED,
1764                                         r->in.domain_sid,
1765                                         &domain_pol,
1766                                         &result);
1767         if (!NT_STATUS_IS_OK(status)) {
1768                 goto done;
1769         }
1770         if (!NT_STATUS_IS_OK(result)) {
1771                 status = result;
1772                 goto done;
1773         }
1774
1775         /* Create domain user */
1776
1777         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1778         if (!strlower_m(acct_name)) {
1779                 status = NT_STATUS_INVALID_PARAMETER;
1780                 goto done;
1781         }
1782
1783         init_lsa_String(&lsa_acct_name, acct_name);
1784
1785         status = dcerpc_samr_LookupNames(b, mem_ctx,
1786                                          &domain_pol,
1787                                          1,
1788                                          &lsa_acct_name,
1789                                          &user_rids,
1790                                          &name_types,
1791                                          &result);
1792
1793         if (!NT_STATUS_IS_OK(status)) {
1794                 goto done;
1795         }
1796         if (!NT_STATUS_IS_OK(result)) {
1797                 status = result;
1798                 goto done;
1799         }
1800         if (user_rids.count != 1) {
1801                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1802                 goto done;
1803         }
1804         if (name_types.count != 1) {
1805                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1806                 goto done;
1807         }
1808
1809         if (name_types.ids[0] != SID_NAME_USER) {
1810                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1811                         name_types.ids[0]));
1812                 status = NT_STATUS_INVALID_WORKSTATION;
1813                 goto done;
1814         }
1815
1816         user_rid = user_rids.ids[0];
1817
1818         /* Open handle on user */
1819
1820         status = dcerpc_samr_OpenUser(b, mem_ctx,
1821                                       &domain_pol,
1822                                       SEC_FLAG_MAXIMUM_ALLOWED,
1823                                       user_rid,
1824                                       &user_pol,
1825                                       &result);
1826         if (!NT_STATUS_IS_OK(status)) {
1827                 goto done;
1828         }
1829         if (!NT_STATUS_IS_OK(result)) {
1830                 status = result;
1831                 goto done;
1832         }
1833
1834         /* Get user info */
1835
1836         status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1837                                            &user_pol,
1838                                            16,
1839                                            &info,
1840                                            &result);
1841         if (!NT_STATUS_IS_OK(status)) {
1842                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1843                 goto done;
1844         }
1845         if (!NT_STATUS_IS_OK(result)) {
1846                 status = result;
1847                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1848                 goto done;
1849         }
1850
1851         /* now disable and setuser info */
1852
1853         info->info16.acct_flags |= ACB_DISABLED;
1854
1855         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1856                                          &user_pol,
1857                                          16,
1858                                          info,
1859                                          &result);
1860         if (!NT_STATUS_IS_OK(status)) {
1861                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1862                 goto done;
1863         }
1864         if (!NT_STATUS_IS_OK(result)) {
1865                 status = result;
1866                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1867                 goto done;
1868         }
1869         status = result;
1870         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1871
1872 done:
1873         if (pipe_hnd && b) {
1874                 if (is_valid_policy_hnd(&domain_pol)) {
1875                         dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1876                 }
1877                 if (is_valid_policy_hnd(&sam_pol)) {
1878                         dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1879                 }
1880                 TALLOC_FREE(pipe_hnd);
1881         }
1882
1883         if (cli) {
1884                 cli_shutdown(cli);
1885         }
1886
1887         return status;
1888 }
1889
1890 /****************************************************************
1891 ****************************************************************/
1892
1893 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1894 {
1895         WERROR werr = WERR_OK;
1896         sbcErr err;
1897         struct smbconf_ctx *ctx;
1898
1899         err = smbconf_init_reg(r, &ctx, NULL);
1900         if (!SBC_ERROR_IS_OK(err)) {
1901                 werr = WERR_NO_SUCH_SERVICE;
1902                 goto done;
1903         }
1904
1905         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1906
1907                 err = smbconf_set_global_parameter(ctx, "security", "user");
1908                 if (!SBC_ERROR_IS_OK(err)) {
1909                         werr = WERR_NO_SUCH_SERVICE;
1910                         goto done;
1911                 }
1912
1913                 err = smbconf_set_global_parameter(ctx, "workgroup",
1914                                                    r->in.domain_name);
1915                 if (!SBC_ERROR_IS_OK(err)) {
1916                         werr = WERR_NO_SUCH_SERVICE;
1917                         goto done;
1918                 }
1919
1920                 smbconf_delete_global_parameter(ctx, "realm");
1921                 goto done;
1922         }
1923
1924         err = smbconf_set_global_parameter(ctx, "security", "domain");
1925         if (!SBC_ERROR_IS_OK(err)) {
1926                 werr = WERR_NO_SUCH_SERVICE;
1927                 goto done;
1928         }
1929
1930         err = smbconf_set_global_parameter(ctx, "workgroup",
1931                                            r->out.netbios_domain_name);
1932         if (!SBC_ERROR_IS_OK(err)) {
1933                 werr = WERR_NO_SUCH_SERVICE;
1934                 goto done;
1935         }
1936
1937         if (r->out.domain_is_ad) {
1938                 err = smbconf_set_global_parameter(ctx, "security", "ads");
1939                 if (!SBC_ERROR_IS_OK(err)) {
1940                         werr = WERR_NO_SUCH_SERVICE;
1941                         goto done;
1942                 }
1943
1944                 err = smbconf_set_global_parameter(ctx, "realm",
1945                                                    r->out.dns_domain_name);
1946                 if (!SBC_ERROR_IS_OK(err)) {
1947                         werr = WERR_NO_SUCH_SERVICE;
1948                         goto done;
1949                 }
1950         }
1951
1952  done:
1953         smbconf_shutdown(ctx);
1954         return werr;
1955 }
1956
1957 /****************************************************************
1958 ****************************************************************/
1959
1960 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1961 {
1962         WERROR werr = WERR_OK;
1963         sbcErr err;
1964         struct smbconf_ctx *ctx;
1965
1966         err = smbconf_init_reg(r, &ctx, NULL);
1967         if (!SBC_ERROR_IS_OK(err)) {
1968                 werr = WERR_NO_SUCH_SERVICE;
1969                 goto done;
1970         }
1971
1972         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1973
1974                 err = smbconf_set_global_parameter(ctx, "security", "user");
1975                 if (!SBC_ERROR_IS_OK(err)) {
1976                         werr = WERR_NO_SUCH_SERVICE;
1977                         goto done;
1978                 }
1979
1980                 err = smbconf_delete_global_parameter(ctx, "workgroup");
1981                 if (!SBC_ERROR_IS_OK(err)) {
1982                         werr = WERR_NO_SUCH_SERVICE;
1983                         goto done;
1984                 }
1985
1986                 smbconf_delete_global_parameter(ctx, "realm");
1987         }
1988
1989  done:
1990         smbconf_shutdown(ctx);
1991         return werr;
1992 }
1993
1994 /****************************************************************
1995 ****************************************************************/
1996
1997 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1998 {
1999         WERROR werr;
2000
2001         if (!W_ERROR_IS_OK(r->out.result)) {
2002                 return r->out.result;
2003         }
2004
2005         if (!r->in.modify_config) {
2006                 return WERR_OK;
2007         }
2008
2009         werr = do_join_modify_vals_config(r);
2010         if (!W_ERROR_IS_OK(werr)) {
2011                 return werr;
2012         }
2013
2014         lp_load_global(get_dyn_CONFIGFILE());
2015
2016         r->out.modified_config = true;
2017         r->out.result = werr;
2018
2019         return werr;
2020 }
2021
2022 /****************************************************************
2023 ****************************************************************/
2024
2025 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2026 {
2027         WERROR werr;
2028
2029         if (!W_ERROR_IS_OK(r->out.result)) {
2030                 return r->out.result;
2031         }
2032
2033         if (!r->in.modify_config) {
2034                 return WERR_OK;
2035         }
2036
2037         werr = do_unjoin_modify_vals_config(r);
2038         if (!W_ERROR_IS_OK(werr)) {
2039                 return werr;
2040         }
2041
2042         lp_load_global(get_dyn_CONFIGFILE());
2043
2044         r->out.modified_config = true;
2045         r->out.result = werr;
2046
2047         return werr;
2048 }
2049
2050 /****************************************************************
2051 ****************************************************************/
2052
2053 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2054                                    const char *domain_str,
2055                                    const char **domain_p,
2056                                    const char **dc_p)
2057 {
2058         char *domain = NULL;
2059         char *dc = NULL;
2060         const char *p = NULL;
2061
2062         if (!domain_str || !domain_p || !dc_p) {
2063                 return false;
2064         }
2065
2066         p = strchr_m(domain_str, '\\');
2067
2068         if (p != NULL) {
2069                 domain = talloc_strndup(mem_ctx, domain_str,
2070                                          PTR_DIFF(p, domain_str));
2071                 dc = talloc_strdup(mem_ctx, p+1);
2072                 if (!dc) {
2073                         return false;
2074                 }
2075         } else {
2076                 domain = talloc_strdup(mem_ctx, domain_str);
2077                 dc = NULL;
2078         }
2079         if (!domain) {
2080                 return false;
2081         }
2082
2083         *domain_p = domain;
2084
2085         if (!*dc_p && dc) {
2086                 *dc_p = dc;
2087         }
2088
2089         return true;
2090 }
2091
2092 /****************************************************************
2093 ****************************************************************/
2094
2095 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2096                                          struct libnet_JoinCtx *r)
2097 {
2098         if (!r->in.domain_name) {
2099                 libnet_join_set_error_string(mem_ctx, r,
2100                         "No domain name defined");
2101                 return WERR_INVALID_PARAM;
2102         }
2103
2104         if (strlen(r->in.machine_name) > 15) {
2105                 libnet_join_set_error_string(mem_ctx, r,
2106                         "Our netbios name can be at most 15 chars long, "
2107                          "\"%s\" is %u chars long\n",
2108                          r->in.machine_name,
2109                          (unsigned int)strlen(r->in.machine_name));
2110                 return WERR_INVALID_PARAM;
2111         }
2112
2113         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2114                                     &r->in.domain_name,
2115                                     &r->in.dc_name)) {
2116                 libnet_join_set_error_string(mem_ctx, r,
2117                         "Failed to parse domain name");
2118                 return WERR_INVALID_PARAM;
2119         }
2120
2121         if (!r->in.admin_domain) {
2122                 char *admin_domain = NULL;
2123                 char *admin_account = NULL;
2124                 split_domain_user(mem_ctx,
2125                                   r->in.admin_account,
2126                                   &admin_domain,
2127                                   &admin_account);
2128                 r->in.admin_domain = admin_domain;
2129                 r->in.admin_account = admin_account;
2130         }
2131
2132         if (!secrets_init()) {
2133                 libnet_join_set_error_string(mem_ctx, r,
2134                         "Unable to open secrets database");
2135                 return WERR_CAN_NOT_COMPLETE;
2136         }
2137
2138         return WERR_OK;
2139 }
2140
2141 /****************************************************************
2142 ****************************************************************/
2143
2144 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2145 {
2146         NTSTATUS status;
2147
2148         /* Try adding dom admins to builtin\admins. Only log failures. */
2149         status = create_builtin_administrators(domain_sid);
2150         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2151                 DEBUG(10,("Unable to auto-add domain administrators to "
2152                           "BUILTIN\\Administrators during join because "
2153                           "winbindd must be running.\n"));
2154         } else if (!NT_STATUS_IS_OK(status)) {
2155                 DEBUG(5, ("Failed to auto-add domain administrators to "
2156                           "BUILTIN\\Administrators during join: %s\n",
2157                           nt_errstr(status)));
2158         }
2159
2160         /* Try adding dom users to builtin\users. Only log failures. */
2161         status = create_builtin_users(domain_sid);
2162         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2163                 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2164                           "during join because winbindd must be running.\n"));
2165         } else if (!NT_STATUS_IS_OK(status)) {
2166                 DEBUG(5, ("Failed to auto-add domain administrators to "
2167                           "BUILTIN\\Administrators during join: %s\n",
2168                           nt_errstr(status)));
2169         }
2170 }
2171
2172 /****************************************************************
2173 ****************************************************************/
2174
2175 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2176                                           struct libnet_JoinCtx *r)
2177 {
2178         WERROR werr;
2179
2180         if (!W_ERROR_IS_OK(r->out.result)) {
2181                 return r->out.result;
2182         }
2183
2184         werr = do_JoinConfig(r);
2185         if (!W_ERROR_IS_OK(werr)) {
2186                 return werr;
2187         }
2188
2189         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2190                 return WERR_OK;
2191         }
2192
2193         saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2194         if (r->out.dns_domain_name) {
2195                 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2196         }
2197
2198 #ifdef HAVE_ADS
2199         if (r->out.domain_is_ad &&
2200             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2201                 ADS_STATUS ads_status;
2202
2203                 ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
2204                 if (!ADS_ERR_OK(ads_status)) {
2205                         return WERR_GENERAL_FAILURE;
2206                 }
2207         }
2208 #endif /* HAVE_ADS */
2209
2210         libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2211
2212         return WERR_OK;
2213 }
2214
2215 /****************************************************************
2216 ****************************************************************/
2217
2218 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2219 {
2220         if (r->in.ads) {
2221                 ads_destroy(&r->in.ads);
2222         }
2223
2224         return 0;
2225 }
2226
2227 /****************************************************************
2228 ****************************************************************/
2229
2230 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2231 {
2232         if (r->in.ads) {
2233                 ads_destroy(&r->in.ads);
2234         }
2235
2236         return 0;
2237 }
2238
2239 /****************************************************************
2240 ****************************************************************/
2241
2242 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2243                            struct libnet_JoinCtx **r)
2244 {
2245         struct libnet_JoinCtx *ctx;
2246
2247         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2248         if (!ctx) {
2249                 return WERR_NOMEM;
2250         }
2251
2252         talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2253
2254         ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2255         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2256
2257         ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2258
2259         ctx->in.desired_encryption_types = ENC_CRC32 |
2260                                            ENC_RSA_MD5 |
2261                                            ENC_RC4_HMAC_MD5;
2262 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
2263         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2264 #endif
2265 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
2266         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2267 #endif
2268
2269         *r = ctx;
2270
2271         return WERR_OK;
2272 }
2273
2274 /****************************************************************
2275 ****************************************************************/
2276
2277 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2278                              struct libnet_UnjoinCtx **r)
2279 {
2280         struct libnet_UnjoinCtx *ctx;
2281
2282         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2283         if (!ctx) {
2284                 return WERR_NOMEM;
2285         }
2286
2287         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2288
2289         ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2290         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2291
2292         *r = ctx;
2293
2294         return WERR_OK;
2295 }
2296
2297 /****************************************************************
2298 ****************************************************************/
2299
2300 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2301                                        struct libnet_JoinCtx *r)
2302 {
2303         bool valid_security = false;
2304         bool valid_workgroup = false;
2305         bool valid_realm = false;
2306         bool ignored_realm = false;
2307
2308         /* check if configuration is already set correctly */
2309
2310         valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2311
2312         switch (r->out.domain_is_ad) {
2313                 case false:
2314                         valid_security = (lp_security() == SEC_DOMAIN)
2315                                 || (lp_server_role() == ROLE_DOMAIN_PDC)
2316                                 || (lp_server_role() == ROLE_DOMAIN_BDC);
2317                         if (valid_workgroup && valid_security) {
2318                                 /* nothing to be done */
2319                                 return WERR_OK;
2320                         }
2321                         break;
2322                 case true:
2323                         valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2324                         switch (lp_security()) {
2325                         case SEC_DOMAIN:
2326                                 if (!valid_realm && lp_winbind_rpc_only()) {
2327                                         valid_realm = true;
2328                                         ignored_realm = true;
2329                                 }
2330                                 /* FALL THROUGH */
2331                         case SEC_ADS:
2332                                 valid_security = true;
2333                         }
2334
2335                         if (valid_workgroup && valid_realm && valid_security) {
2336                                 if (ignored_realm && !r->in.modify_config)
2337                                 {
2338                                         libnet_join_set_error_string(mem_ctx, r,
2339                                                 "Warning: ignoring realm when "
2340                                                 "joining AD domain with "
2341                                                 "'security=domain' and "
2342                                                 "'winbind rpc only = yes'. "
2343                                                 "(realm set to '%s', "
2344                                                 "should be '%s').", lp_realm(),
2345                                                 r->out.dns_domain_name);
2346                                 }
2347                                 /* nothing to be done */
2348                                 return WERR_OK;
2349                         }
2350                         break;
2351         }
2352
2353         /* check if we are supposed to manipulate configuration */
2354
2355         if (!r->in.modify_config) {
2356
2357                 char *wrong_conf = talloc_strdup(mem_ctx, "");
2358
2359                 if (!valid_workgroup) {
2360                         wrong_conf = talloc_asprintf_append(wrong_conf,
2361                                 "\"workgroup\" set to '%s', should be '%s'",
2362                                 lp_workgroup(), r->out.netbios_domain_name);
2363                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2364                 }
2365
2366                 if (!valid_realm) {
2367                         wrong_conf = talloc_asprintf_append(wrong_conf,
2368                                 "\"realm\" set to '%s', should be '%s'",
2369                                 lp_realm(), r->out.dns_domain_name);
2370                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2371                 }
2372
2373                 if (!valid_security) {
2374                         const char *sec = NULL;
2375                         switch (lp_security()) {
2376                         case SEC_USER:  sec = "user"; break;
2377                         case SEC_DOMAIN: sec = "domain"; break;
2378                         case SEC_ADS: sec = "ads"; break;
2379                         }
2380                         wrong_conf = talloc_asprintf_append(wrong_conf,
2381                                 "\"security\" set to '%s', should be %s",
2382                                 sec, r->out.domain_is_ad ?
2383                                 "either 'domain' or 'ads'" : "'domain'");
2384                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2385                 }
2386
2387                 libnet_join_set_error_string(mem_ctx, r,
2388                         "Invalid configuration (%s) and configuration modification "
2389                         "was not requested", wrong_conf);
2390                 return WERR_CAN_NOT_COMPLETE;
2391         }
2392
2393         /* check if we are able to manipulate configuration */
2394
2395         if (!lp_config_backend_is_registry()) {
2396                 libnet_join_set_error_string(mem_ctx, r,
2397                         "Configuration manipulation requested but not "
2398                         "supported by backend");
2399                 return WERR_NOT_SUPPORTED;
2400         }
2401
2402         return WERR_OK;
2403 }
2404
2405 /****************************************************************
2406 ****************************************************************/
2407
2408 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2409                                 struct libnet_JoinCtx *r)
2410 {
2411         NTSTATUS status;
2412         WERROR werr;
2413         struct cli_state *cli = NULL;
2414 #ifdef HAVE_ADS
2415         ADS_STATUS ads_status;
2416 #endif /* HAVE_ADS */
2417         const char *pre_connect_realm = NULL;
2418         const char *numeric_dcip = NULL;
2419         const char *sitename = NULL;
2420
2421         /* Before contacting a DC, we can securely know
2422          * the realm only if the user specifies it.
2423          */
2424         if (r->in.use_kerberos &&
2425             r->in.domain_name_type == JoinDomNameTypeDNS) {
2426                 pre_connect_realm = r->in.domain_name;
2427         }
2428
2429         if (!r->in.dc_name) {
2430                 struct netr_DsRGetDCNameInfo *info;
2431                 const char *dc;
2432                 uint32_t name_type_flags = 0;
2433                 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2434                         name_type_flags = DS_IS_DNS_NAME;
2435                 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2436                         name_type_flags = DS_IS_FLAT_NAME;
2437                 }
2438                 status = dsgetdcname(mem_ctx,
2439                                      r->in.msg_ctx,
2440                                      r->in.domain_name,
2441                                      NULL,
2442                                      NULL,
2443                                      DS_FORCE_REDISCOVERY |
2444                                      DS_DIRECTORY_SERVICE_REQUIRED |
2445                                      DS_WRITABLE_REQUIRED |
2446                                      DS_RETURN_DNS_NAME |
2447                                      name_type_flags,
2448                                      &info);
2449                 if (!NT_STATUS_IS_OK(status)) {
2450                         libnet_join_set_error_string(mem_ctx, r,
2451                                 "failed to find DC for domain %s - %s",
2452                                 r->in.domain_name,
2453                                 get_friendly_nt_error_msg(status));
2454                         return WERR_DCNOTFOUND;
2455                 }
2456
2457                 dc = strip_hostname(info->dc_unc);
2458                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2459                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2460
2461                 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2462                     info->dc_address[1] != '\\') {
2463                         DBG_ERR("ill-formed DC address '%s'\n",
2464                                 info->dc_address);
2465                         return WERR_DCNOTFOUND;
2466                 }
2467
2468                 numeric_dcip = info->dc_address + 2;
2469                 sitename = info->dc_site_name;
2470                 /* info goes out of scope but the memory stays
2471                    allocated on the talloc context */
2472         }
2473
2474         if (pre_connect_realm != NULL) {
2475                 struct sockaddr_storage ss = {0};
2476
2477                 if (numeric_dcip != NULL) {
2478                         if (!interpret_string_addr(&ss, numeric_dcip,
2479                                                    AI_NUMERICHOST)) {
2480                                 DBG_ERR(
2481                                     "cannot parse IP address '%s' of DC '%s'\n",
2482                                     numeric_dcip, r->in.dc_name);
2483                                 return WERR_DCNOTFOUND;
2484                         }
2485                 } else {
2486                         if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2487                                 DBG_WARNING(
2488                                     "cannot resolve IP address of DC '%s'\n",
2489                                     r->in.dc_name);
2490                                 return WERR_DCNOTFOUND;
2491                         }
2492                 }
2493
2494                 /* The domain parameter is only used as modifier
2495                  * to krb5.conf file name. .JOIN is is not a valid
2496                  * NetBIOS name so it cannot clash with another domain
2497                  * -- Uri.
2498                  */
2499                 create_local_private_krb5_conf_for_domain(
2500                     pre_connect_realm, ".JOIN", sitename, &ss);
2501         }
2502
2503         status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2504         if (!NT_STATUS_IS_OK(status)) {
2505                 libnet_join_set_error_string(mem_ctx, r,
2506                         "failed to lookup DC info for domain '%s' over rpc: %s",
2507                         r->in.domain_name, get_friendly_nt_error_msg(status));
2508                 return ntstatus_to_werror(status);
2509         }
2510
2511         werr = libnet_join_check_config(mem_ctx, r);
2512         if (!W_ERROR_IS_OK(werr)) {
2513                 goto done;
2514         }
2515
2516 #ifdef HAVE_ADS
2517
2518         if (r->out.domain_is_ad) {
2519                 create_local_private_krb5_conf_for_domain(
2520                         r->out.dns_domain_name, r->out.netbios_domain_name,
2521                         sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2522         }
2523
2524         if (r->out.domain_is_ad &&
2525             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2526
2527                 const char *initial_account_ou = r->in.account_ou;
2528
2529                 /*
2530                  * we want to create the msDS-SupportedEncryptionTypes attribute
2531                  * as early as possible so always try an LDAP create as the user
2532                  * first. We copy r->in.account_ou because it may be changed
2533                  * during the machine pre-creation.
2534                  */
2535
2536                 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2537                 if (!ADS_ERR_OK(ads_status)) {
2538                         return WERR_DEFAULT_JOIN_REQUIRED;
2539                 }
2540
2541                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2542                 if (ADS_ERR_OK(ads_status)) {
2543
2544                         /*
2545                          * LDAP object create succeeded, now go to the rpc
2546                          * password set routines
2547                          */
2548
2549                         r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2550                         goto rpc_join;
2551                 }
2552
2553                 if (initial_account_ou != NULL) {
2554                         libnet_join_set_error_string(mem_ctx, r,
2555                                 "failed to precreate account in ou %s: %s",
2556                                 r->in.account_ou,
2557                                 ads_errstr(ads_status));
2558                         return WERR_DEFAULT_JOIN_REQUIRED;
2559                 }
2560
2561                 DEBUG(5, ("failed to precreate account in ou %s: %s",
2562                         r->in.account_ou, ads_errstr(ads_status)));
2563         }
2564 #endif /* HAVE_ADS */
2565
2566  rpc_join:
2567         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2568             (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2569                 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2570         } else {
2571                 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2572         }
2573         if (!NT_STATUS_IS_OK(status)) {
2574                 libnet_join_set_error_string(mem_ctx, r,
2575                         "failed to join domain '%s' over rpc: %s",
2576                         r->in.domain_name, get_friendly_nt_error_msg(status));
2577                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2578                         return WERR_SETUP_ALREADY_JOINED;
2579                 }
2580                 werr = ntstatus_to_werror(status);
2581                 goto done;
2582         }
2583
2584         if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2585                 werr = WERR_SETUP_NOT_JOINED;
2586                 goto done;
2587         }
2588
2589         werr = WERR_OK;
2590
2591  done:
2592         if (cli) {
2593                 cli_shutdown(cli);
2594         }
2595
2596         return werr;
2597 }
2598
2599 /****************************************************************
2600 ****************************************************************/
2601
2602 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2603                                    struct libnet_JoinCtx *r)
2604 {
2605         WERROR werr;
2606         struct libnet_UnjoinCtx *u = NULL;
2607
2608         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2609         if (!W_ERROR_IS_OK(werr)) {
2610                 return werr;
2611         }
2612
2613         u->in.debug             = r->in.debug;
2614         u->in.dc_name           = r->in.dc_name;
2615         u->in.domain_name       = r->in.domain_name;
2616         u->in.admin_account     = r->in.admin_account;
2617         u->in.admin_password    = r->in.admin_password;
2618         u->in.modify_config     = r->in.modify_config;
2619         u->in.use_kerberos      = r->in.use_kerberos;
2620         u->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2621                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2622
2623         werr = libnet_Unjoin(mem_ctx, u);
2624         TALLOC_FREE(u);
2625
2626         return werr;
2627 }
2628
2629 /****************************************************************
2630 ****************************************************************/
2631
2632 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2633                    struct libnet_JoinCtx *r)
2634 {
2635         WERROR werr;
2636
2637         if (r->in.debug) {
2638                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2639         }
2640
2641         ZERO_STRUCT(r->out);
2642
2643         werr = libnet_join_pre_processing(mem_ctx, r);
2644         if (!W_ERROR_IS_OK(werr)) {
2645                 goto done;
2646         }
2647
2648         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2649                 werr = libnet_DomainJoin(mem_ctx, r);
2650                 if (!W_ERROR_IS_OK(werr)) {
2651                         goto done;
2652                 }
2653         }
2654
2655         werr = libnet_join_post_processing(mem_ctx, r);
2656         if (!W_ERROR_IS_OK(werr)) {
2657                 goto done;
2658         }
2659
2660         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2661                 werr = libnet_join_post_verify(mem_ctx, r);
2662                 if (!W_ERROR_IS_OK(werr)) {
2663                         libnet_join_rollback(mem_ctx, r);
2664                 }
2665         }
2666
2667  done:
2668         r->out.result = werr;
2669
2670         if (r->in.debug) {
2671                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2672         }
2673         return werr;
2674 }
2675
2676 /****************************************************************
2677 ****************************************************************/
2678
2679 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2680                                   struct libnet_UnjoinCtx *r)
2681 {
2682         NTSTATUS status;
2683
2684         if (!r->in.domain_sid) {
2685                 struct dom_sid sid;
2686                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2687                         libnet_unjoin_set_error_string(mem_ctx, r,
2688                                 "Unable to fetch domain sid: are we joined?");
2689                         return WERR_SETUP_NOT_JOINED;
2690                 }
2691                 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2692                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2693         }
2694
2695         if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && 
2696             !r->in.delete_machine_account) {
2697                 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2698                 return WERR_OK;
2699         }
2700
2701         if (!r->in.dc_name) {
2702                 struct netr_DsRGetDCNameInfo *info;
2703                 const char *dc;
2704                 status = dsgetdcname(mem_ctx,
2705                                      r->in.msg_ctx,
2706                                      r->in.domain_name,
2707                                      NULL,
2708                                      NULL,
2709                                      DS_DIRECTORY_SERVICE_REQUIRED |
2710                                      DS_WRITABLE_REQUIRED |
2711                                      DS_RETURN_DNS_NAME,
2712                                      &info);
2713                 if (!NT_STATUS_IS_OK(status)) {
2714                         libnet_unjoin_set_error_string(mem_ctx, r,
2715                                 "failed to find DC for domain %s - %s",
2716                                 r->in.domain_name,
2717                                 get_friendly_nt_error_msg(status));
2718                         return WERR_DCNOTFOUND;
2719                 }
2720
2721                 dc = strip_hostname(info->dc_unc);
2722                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2723                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2724         }
2725
2726 #ifdef HAVE_ADS
2727         /* for net ads leave, try to delete the account.  If it works, 
2728            no sense in disabling.  If it fails, we can still try to 
2729            disable it. jmcd */
2730
2731         if (r->in.delete_machine_account) {
2732                 ADS_STATUS ads_status;
2733                 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2734                 if (ADS_ERR_OK(ads_status)) {
2735                         /* dirty hack */
2736                         r->out.dns_domain_name = 
2737                                 talloc_strdup(mem_ctx,
2738                                               r->in.ads->server.realm);
2739                         ads_status = 
2740                                 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2741                 }
2742                 if (!ADS_ERR_OK(ads_status)) {
2743                         libnet_unjoin_set_error_string(mem_ctx, r,
2744                                 "failed to remove machine account from AD: %s",
2745                                 ads_errstr(ads_status));
2746                 } else {
2747                         r->out.deleted_machine_account = true;
2748                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2749                         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2750                         return WERR_OK;
2751                 }
2752         }
2753 #endif /* HAVE_ADS */
2754
2755         /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means 
2756            "disable".  */
2757         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2758                 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2759                 if (!NT_STATUS_IS_OK(status)) {
2760                         libnet_unjoin_set_error_string(mem_ctx, r,
2761                                 "failed to disable machine account via rpc: %s",
2762                                 get_friendly_nt_error_msg(status));
2763                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2764                                 return WERR_SETUP_NOT_JOINED;
2765                         }
2766                         return ntstatus_to_werror(status);
2767                 }
2768
2769                 r->out.disabled_machine_account = true;
2770         }
2771
2772         /* If disable succeeded or was not requested at all, we 
2773            should be getting rid of our end of things */
2774
2775         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2776
2777         return WERR_OK;
2778 }
2779
2780 /****************************************************************
2781 ****************************************************************/
2782
2783 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2784                                            struct libnet_UnjoinCtx *r)
2785 {
2786         if (!r->in.domain_name) {
2787                 libnet_unjoin_set_error_string(mem_ctx, r,
2788                         "No domain name defined");
2789                 return WERR_INVALID_PARAM;
2790         }
2791
2792         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2793                                     &r->in.domain_name,
2794                                     &r->in.dc_name)) {
2795                 libnet_unjoin_set_error_string(mem_ctx, r,
2796                         "Failed to parse domain name");
2797                 return WERR_INVALID_PARAM;
2798         }
2799
2800         if (IS_DC) {
2801                 return WERR_SETUP_DOMAIN_CONTROLLER;
2802         }
2803
2804         if (!r->in.admin_domain) {
2805                 char *admin_domain = NULL;
2806                 char *admin_account = NULL;
2807                 split_domain_user(mem_ctx,
2808                                   r->in.admin_account,
2809                                   &admin_domain,
2810                                   &admin_account);
2811                 r->in.admin_domain = admin_domain;
2812                 r->in.admin_account = admin_account;
2813         }
2814
2815         if (!secrets_init()) {
2816                 libnet_unjoin_set_error_string(mem_ctx, r,
2817                         "Unable to open secrets database");
2818                 return WERR_CAN_NOT_COMPLETE;
2819         }
2820
2821         return WERR_OK;
2822 }
2823
2824 /****************************************************************
2825 ****************************************************************/
2826
2827 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2828                                             struct libnet_UnjoinCtx *r)
2829 {
2830         saf_delete(r->out.netbios_domain_name);
2831         saf_delete(r->out.dns_domain_name);
2832
2833         return libnet_unjoin_config(r);
2834 }
2835
2836 /****************************************************************
2837 ****************************************************************/
2838
2839 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2840                      struct libnet_UnjoinCtx *r)
2841 {
2842         WERROR werr;
2843
2844         if (r->in.debug) {
2845                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2846         }
2847
2848         werr = libnet_unjoin_pre_processing(mem_ctx, r);
2849         if (!W_ERROR_IS_OK(werr)) {
2850                 goto done;
2851         }
2852
2853         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2854                 werr = libnet_DomainUnjoin(mem_ctx, r);
2855                 if (!W_ERROR_IS_OK(werr)) {
2856                         libnet_unjoin_config(r);
2857                         goto done;
2858                 }
2859         }
2860
2861         werr = libnet_unjoin_post_processing(mem_ctx, r);
2862         if (!W_ERROR_IS_OK(werr)) {
2863                 goto done;
2864         }
2865
2866  done:
2867         r->out.result = werr;
2868
2869         if (r->in.debug) {
2870                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2871         }
2872
2873         return werr;
2874 }