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