381a59ce6cd3b90b9f0a678ca39e21a0ced81015
[samba.git] / source3 / libnet / libnet_join.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet Join Support
4  *  Copyright (C) Gerald (Jerry) Carter 2006
5  *  Copyright (C) Guenther Deschner 2007-2008
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "ads.h"
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
35 #include "secrets.h"
36 #include "rpc_client/init_lsa.h"
37 #include "rpc_client/cli_pipe.h"
38 #include "../libcli/security/security.h"
39 #include "passdb.h"
40 #include "libsmb/libsmb.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/param/loadparm.h"
43 #include "libcli/auth/netlogon_creds_cli.h"
44 #include "auth/credentials/credentials.h"
45
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, (int *)&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, (int *)&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 bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
609                                       struct libnet_JoinCtx *r)
610 {
611         if (!USE_SYSTEM_KEYTAB) {
612                 return true;
613         }
614
615         if (ads_keytab_create_default(r->in.ads) != 0) {
616                 return false;
617         }
618
619         return true;
620 }
621
622 /****************************************************************
623 ****************************************************************/
624
625 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
626                                                  struct libnet_JoinCtx *r)
627 {
628         uint32_t domain_func;
629         ADS_STATUS status;
630         const char *salt = NULL;
631         char *std_salt = NULL;
632
633         status = ads_domain_func_level(r->in.ads, &domain_func);
634         if (!ADS_ERR_OK(status)) {
635                 libnet_join_set_error_string(mem_ctx, r,
636                         "failed to determine domain functional level: %s",
637                         ads_errstr(status));
638                 return false;
639         }
640
641         /* go ahead and setup the default salt */
642
643         std_salt = kerberos_standard_des_salt();
644         if (!std_salt) {
645                 libnet_join_set_error_string(mem_ctx, r,
646                         "failed to obtain standard DES salt");
647                 return false;
648         }
649
650         salt = talloc_strdup(mem_ctx, std_salt);
651         if (!salt) {
652                 return false;
653         }
654
655         SAFE_FREE(std_salt);
656
657         /* if it's a Windows functional domain, we have to look for the UPN */
658
659         if (domain_func == DS_DOMAIN_FUNCTION_2000) {
660                 char *upn;
661
662                 upn = ads_get_upn(r->in.ads, mem_ctx,
663                                   r->in.machine_name);
664                 if (upn) {
665                         salt = talloc_strdup(mem_ctx, upn);
666                         if (!salt) {
667                                 return false;
668                         }
669                 }
670         }
671
672         return kerberos_secrets_store_des_salt(salt);
673 }
674
675 /****************************************************************
676 ****************************************************************/
677
678 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
679                                                   struct libnet_JoinCtx *r)
680 {
681         ADS_STATUS status;
682
683         if (!r->in.ads) {
684                 status = libnet_join_connect_ads(mem_ctx, r);
685                 if (!ADS_ERR_OK(status)) {
686                         return status;
687                 }
688         }
689
690         status = libnet_join_set_machine_spn(mem_ctx, r);
691         if (!ADS_ERR_OK(status)) {
692                 libnet_join_set_error_string(mem_ctx, r,
693                         "Failed to set machine spn: %s\n"
694                         "Do you have sufficient permissions to create machine "
695                         "accounts?",
696                         ads_errstr(status));
697                 return status;
698         }
699
700         status = libnet_join_set_os_attributes(mem_ctx, r);
701         if (!ADS_ERR_OK(status)) {
702                 libnet_join_set_error_string(mem_ctx, r,
703                         "failed to set machine os attributes: %s",
704                         ads_errstr(status));
705                 return status;
706         }
707
708         status = libnet_join_set_machine_upn(mem_ctx, r);
709         if (!ADS_ERR_OK(status)) {
710                 libnet_join_set_error_string(mem_ctx, r,
711                         "failed to set machine upn: %s",
712                         ads_errstr(status));
713                 return status;
714         }
715
716         if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
717                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
718         }
719
720         if (!libnet_join_create_keytab(mem_ctx, r)) {
721                 libnet_join_set_error_string(mem_ctx, r,
722                         "failed to create kerberos keytab");
723                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
724         }
725
726         return ADS_SUCCESS;
727 }
728 #endif /* HAVE_ADS */
729
730 /****************************************************************
731  Store the machine password and domain SID
732 ****************************************************************/
733
734 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
735                                                  struct libnet_JoinCtx *r)
736 {
737         if (!secrets_store_domain_sid(r->out.netbios_domain_name,
738                                       r->out.domain_sid))
739         {
740                 DEBUG(1,("Failed to save domain sid\n"));
741                 return false;
742         }
743
744         if (!secrets_store_machine_password(r->in.machine_password,
745                                             r->out.netbios_domain_name,
746                                             r->in.secure_channel_type))
747         {
748                 DEBUG(1,("Failed to save machine password\n"));
749                 return false;
750         }
751
752         return true;
753 }
754
755 /****************************************************************
756  Connect dc's IPC$ share
757 ****************************************************************/
758
759 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
760                                            const char *user,
761                                            const char *domain,
762                                            const char *pass,
763                                            bool use_kerberos,
764                                            struct cli_state **cli)
765 {
766         int flags = 0;
767
768         if (use_kerberos) {
769                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
770         }
771
772         if (use_kerberos && pass) {
773                 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
774         }
775
776         return cli_full_connection(cli, NULL,
777                                    dc,
778                                    NULL, 0,
779                                    "IPC$", "IPC",
780                                    user,
781                                    domain,
782                                    pass,
783                                    flags,
784                                    SMB_SIGNING_DEFAULT);
785 }
786
787 /****************************************************************
788  Lookup domain dc's info
789 ****************************************************************/
790
791 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
792                                           struct libnet_JoinCtx *r,
793                                           struct cli_state **cli)
794 {
795         struct rpc_pipe_client *pipe_hnd = NULL;
796         struct policy_handle lsa_pol;
797         NTSTATUS status, result;
798         union lsa_PolicyInformation *info = NULL;
799         struct dcerpc_binding_handle *b;
800
801         status = libnet_join_connect_dc_ipc(r->in.dc_name,
802                                             r->in.admin_account,
803                                             r->in.admin_domain,
804                                             r->in.admin_password,
805                                             r->in.use_kerberos,
806                                             cli);
807         if (!NT_STATUS_IS_OK(status)) {
808                 goto done;
809         }
810
811         status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
812                                           &pipe_hnd);
813         if (!NT_STATUS_IS_OK(status)) {
814                 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
815                         nt_errstr(status)));
816                 goto done;
817         }
818
819         b = pipe_hnd->binding_handle;
820
821         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
822                                         SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
823         if (!NT_STATUS_IS_OK(status)) {
824                 goto done;
825         }
826
827         status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
828                                              &lsa_pol,
829                                              LSA_POLICY_INFO_DNS,
830                                              &info,
831                                              &result);
832         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
833                 r->out.domain_is_ad = true;
834                 r->out.netbios_domain_name = info->dns.name.string;
835                 r->out.dns_domain_name = info->dns.dns_domain.string;
836                 r->out.forest_name = info->dns.dns_forest.string;
837                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
838                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
839         }
840
841         if (!NT_STATUS_IS_OK(status)) {
842                 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
843                                                     &lsa_pol,
844                                                     LSA_POLICY_INFO_ACCOUNT_DOMAIN,
845                                                     &info,
846                                                     &result);
847                 if (!NT_STATUS_IS_OK(status)) {
848                         goto done;
849                 }
850                 if (!NT_STATUS_IS_OK(result)) {
851                         status = result;
852                         goto done;
853                 }
854
855                 r->out.netbios_domain_name = info->account_domain.name.string;
856                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
857                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
858         }
859
860         dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
861         TALLOC_FREE(pipe_hnd);
862
863  done:
864         return status;
865 }
866
867 /****************************************************************
868  Do the domain join unsecure
869 ****************************************************************/
870
871 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
872                                                     struct libnet_JoinCtx *r,
873                                                     struct cli_state *cli)
874 {
875         TALLOC_CTX *frame = talloc_stackframe();
876         struct rpc_pipe_client *netlogon_pipe = NULL;
877         struct netlogon_creds_cli_context *netlogon_creds = NULL;
878         struct samr_Password current_nt_hash;
879         const char *account_name = NULL;
880         NTSTATUS status;
881
882         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
883                                           &netlogon_pipe);
884         if (!NT_STATUS_IS_OK(status)) {
885                 TALLOC_FREE(frame);
886                 return status;
887         }
888
889         if (!r->in.machine_password) {
890                 r->in.machine_password = generate_random_password(mem_ctx,
891                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
892                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
893                 if (r->in.machine_password == NULL) {
894                         TALLOC_FREE(frame);
895                         return NT_STATUS_NO_MEMORY;
896                 }
897         }
898
899         /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
900         E_md4hash(r->in.admin_password, current_nt_hash.hash);
901
902         account_name = talloc_asprintf(frame, "%s$",
903                                        r->in.machine_name);
904         if (account_name == NULL) {
905                 TALLOC_FREE(frame);
906                 return NT_STATUS_NO_MEMORY;
907         }
908
909         status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
910                                               r->in.domain_name,
911                                               account_name,
912                                               r->in.secure_channel_type,
913                                               r->in.msg_ctx,
914                                               frame,
915                                               &netlogon_creds);
916         if (!NT_STATUS_IS_OK(status)) {
917                 TALLOC_FREE(frame);
918                 return status;
919         }
920
921         status = rpccli_setup_netlogon_creds(cli,
922                                              netlogon_creds,
923                                              true, /* force_reauth */
924                                              current_nt_hash,
925                                              NULL); /* previous_nt_hash */
926         if (!NT_STATUS_IS_OK(status)) {
927                 TALLOC_FREE(frame);
928                 return status;
929         }
930
931         status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
932                                                       netlogon_pipe->binding_handle,
933                                                       r->in.machine_password,
934                                                       NULL); /* new_version */
935         if (!NT_STATUS_IS_OK(status)) {
936                 TALLOC_FREE(frame);
937                 return status;
938         }
939
940         TALLOC_FREE(frame);
941         return NT_STATUS_OK;
942 }
943
944 /****************************************************************
945  Do the domain join
946 ****************************************************************/
947
948 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
949                                            struct libnet_JoinCtx *r,
950                                            struct cli_state *cli)
951 {
952         struct rpc_pipe_client *pipe_hnd = NULL;
953         struct policy_handle sam_pol, domain_pol, user_pol;
954         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
955         char *acct_name;
956         struct lsa_String lsa_acct_name;
957         uint32_t user_rid;
958         uint32_t acct_flags = ACB_WSTRUST;
959         struct samr_Ids user_rids;
960         struct samr_Ids name_types;
961         union samr_UserInfo user_info;
962         struct dcerpc_binding_handle *b = NULL;
963         unsigned int old_timeout = 0;
964
965         DATA_BLOB session_key = data_blob_null;
966         struct samr_CryptPassword crypt_pwd;
967         struct samr_CryptPasswordEx crypt_pwd_ex;
968
969         ZERO_STRUCT(sam_pol);
970         ZERO_STRUCT(domain_pol);
971         ZERO_STRUCT(user_pol);
972
973         switch (r->in.secure_channel_type) {
974         case SEC_CHAN_WKSTA:
975                 acct_flags = ACB_WSTRUST;
976                 break;
977         case SEC_CHAN_BDC:
978                 acct_flags = ACB_SVRTRUST;
979                 break;
980         default:
981                 return NT_STATUS_INVALID_PARAMETER;
982         }
983
984         if (!r->in.machine_password) {
985                 r->in.machine_password = generate_random_password(mem_ctx,
986                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
987                                 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
988                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
989         }
990
991         /* Open the domain */
992
993         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
994                                           &pipe_hnd);
995         if (!NT_STATUS_IS_OK(status)) {
996                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
997                         nt_errstr(status)));
998                 goto done;
999         }
1000
1001         b = pipe_hnd->binding_handle;
1002
1003         status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1004         if (!NT_STATUS_IS_OK(status)) {
1005                 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1006                         nt_errstr(status)));
1007                 goto done;
1008         }
1009
1010         status = dcerpc_samr_Connect2(b, mem_ctx,
1011                                       pipe_hnd->desthost,
1012                                       SAMR_ACCESS_ENUM_DOMAINS
1013                                       | SAMR_ACCESS_LOOKUP_DOMAIN,
1014                                       &sam_pol,
1015                                       &result);
1016         if (!NT_STATUS_IS_OK(status)) {
1017                 goto done;
1018         }
1019         if (!NT_STATUS_IS_OK(result)) {
1020                 status = result;
1021                 goto done;
1022         }
1023
1024         status = dcerpc_samr_OpenDomain(b, mem_ctx,
1025                                         &sam_pol,
1026                                         SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1027                                         | SAMR_DOMAIN_ACCESS_CREATE_USER
1028                                         | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1029                                         r->out.domain_sid,
1030                                         &domain_pol,
1031                                         &result);
1032         if (!NT_STATUS_IS_OK(status)) {
1033                 goto done;
1034         }
1035         if (!NT_STATUS_IS_OK(result)) {
1036                 status = result;
1037                 goto done;
1038         }
1039
1040         /* Create domain user */
1041
1042         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1043         if (!strlower_m(acct_name)) {
1044                 status = NT_STATUS_INVALID_PARAMETER;
1045                 goto done;
1046         }
1047
1048         init_lsa_String(&lsa_acct_name, acct_name);
1049
1050         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1051                 uint32_t access_desired =
1052                         SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1053                         SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1054                         SAMR_USER_ACCESS_SET_PASSWORD |
1055                         SAMR_USER_ACCESS_GET_ATTRIBUTES |
1056                         SAMR_USER_ACCESS_SET_ATTRIBUTES;
1057                 uint32_t access_granted = 0;
1058
1059                 DEBUG(10,("Creating account with desired access mask: %d\n",
1060                         access_desired));
1061
1062                 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1063                                                  &domain_pol,
1064                                                  &lsa_acct_name,
1065                                                  acct_flags,
1066                                                  access_desired,
1067                                                  &user_pol,
1068                                                  &access_granted,
1069                                                  &user_rid,
1070                                                  &result);
1071                 if (!NT_STATUS_IS_OK(status)) {
1072                         goto done;
1073                 }
1074
1075                 status = result;
1076                 if (!NT_STATUS_IS_OK(status) &&
1077                     !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1078
1079                         DEBUG(10,("Creation of workstation account failed: %s\n",
1080                                 nt_errstr(status)));
1081
1082                         /* If NT_STATUS_ACCESS_DENIED then we have a valid
1083                            username/password combo but the user does not have
1084                            administrator access. */
1085
1086                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1087                                 libnet_join_set_error_string(mem_ctx, r,
1088                                         "User specified does not have "
1089                                         "administrator privileges");
1090                         }
1091
1092                         goto done;
1093                 }
1094
1095                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1096                         if (!(r->in.join_flags &
1097                               WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1098                                 goto done;
1099                         }
1100                 }
1101
1102                 /* We *must* do this.... don't ask... */
1103
1104                 if (NT_STATUS_IS_OK(status)) {
1105                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1106                 }
1107         }
1108
1109         status = dcerpc_samr_LookupNames(b, mem_ctx,
1110                                          &domain_pol,
1111                                          1,
1112                                          &lsa_acct_name,
1113                                          &user_rids,
1114                                          &name_types,
1115                                          &result);
1116         if (!NT_STATUS_IS_OK(status)) {
1117                 goto done;
1118         }
1119         if (!NT_STATUS_IS_OK(result)) {
1120                 status = result;
1121                 goto done;
1122         }
1123         if (user_rids.count != 1) {
1124                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1125                 goto done;
1126         }
1127         if (name_types.count != 1) {
1128                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1129                 goto done;
1130         }
1131
1132         if (name_types.ids[0] != SID_NAME_USER) {
1133                 DEBUG(0,("%s is not a user account (type=%d)\n",
1134                         acct_name, name_types.ids[0]));
1135                 status = NT_STATUS_INVALID_WORKSTATION;
1136                 goto done;
1137         }
1138
1139         user_rid = user_rids.ids[0];
1140
1141         /* Open handle on user */
1142
1143         status = dcerpc_samr_OpenUser(b, mem_ctx,
1144                                       &domain_pol,
1145                                       SEC_FLAG_MAXIMUM_ALLOWED,
1146                                       user_rid,
1147                                       &user_pol,
1148                                       &result);
1149         if (!NT_STATUS_IS_OK(status)) {
1150                 goto done;
1151         }
1152         if (!NT_STATUS_IS_OK(result)) {
1153                 status = result;
1154                 goto done;
1155         }
1156
1157         /* Fill in the additional account flags now */
1158
1159         acct_flags |= ACB_PWNOEXP;
1160
1161         /* Set account flags on machine account */
1162         ZERO_STRUCT(user_info.info16);
1163         user_info.info16.acct_flags = acct_flags;
1164
1165         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1166                                          &user_pol,
1167                                          16,
1168                                          &user_info,
1169                                          &result);
1170         if (!NT_STATUS_IS_OK(status)) {
1171                 dcerpc_samr_DeleteUser(b, mem_ctx,
1172                                        &user_pol,
1173                                        &result);
1174
1175                 libnet_join_set_error_string(mem_ctx, r,
1176                         "Failed to set account flags for machine account (%s)\n",
1177                         nt_errstr(status));
1178                 goto done;
1179         }
1180
1181         if (!NT_STATUS_IS_OK(result)) {
1182                 status = result;
1183
1184                 dcerpc_samr_DeleteUser(b, mem_ctx,
1185                                        &user_pol,
1186                                        &result);
1187
1188                 libnet_join_set_error_string(mem_ctx, r,
1189                         "Failed to set account flags for machine account (%s)\n",
1190                         nt_errstr(status));
1191                 goto done;
1192         }
1193
1194         /* Set password on machine account - first try level 26 */
1195
1196         /*
1197          * increase the timeout as password filter modules on the DC
1198          * might delay the operation for a significant amount of time
1199          */
1200         old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1201
1202         init_samr_CryptPasswordEx(r->in.machine_password,
1203                                   &session_key,
1204                                   &crypt_pwd_ex);
1205
1206         user_info.info26.password = crypt_pwd_ex;
1207         user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1208
1209         status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1210                                           &user_pol,
1211                                           26,
1212                                           &user_info,
1213                                           &result);
1214
1215         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1216
1217                 /* retry with level 24 */
1218
1219                 init_samr_CryptPassword(r->in.machine_password,
1220                                         &session_key,
1221                                         &crypt_pwd);
1222
1223                 user_info.info24.password = crypt_pwd;
1224                 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1225
1226                 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1227                                                   &user_pol,
1228                                                   24,
1229                                                   &user_info,
1230                                                   &result);
1231         }
1232
1233         old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1234
1235         if (!NT_STATUS_IS_OK(status)) {
1236
1237                 dcerpc_samr_DeleteUser(b, mem_ctx,
1238                                        &user_pol,
1239                                        &result);
1240
1241                 libnet_join_set_error_string(mem_ctx, r,
1242                         "Failed to set password for machine account (%s)\n",
1243                         nt_errstr(status));
1244                 goto done;
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 password for machine account (%s)\n",
1255                         nt_errstr(status));
1256                 goto done;
1257         }
1258
1259         status = NT_STATUS_OK;
1260
1261  done:
1262         if (!pipe_hnd) {
1263                 return status;
1264         }
1265
1266         data_blob_clear_free(&session_key);
1267
1268         if (is_valid_policy_hnd(&sam_pol)) {
1269                 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1270         }
1271         if (is_valid_policy_hnd(&domain_pol)) {
1272                 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1273         }
1274         if (is_valid_policy_hnd(&user_pol)) {
1275                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1276         }
1277         TALLOC_FREE(pipe_hnd);
1278
1279         return status;
1280 }
1281
1282 /****************************************************************
1283 ****************************************************************/
1284
1285 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1286                         const char *netbios_domain_name,
1287                         const char *dc_name,
1288                         const bool use_kerberos)
1289 {
1290         TALLOC_CTX *frame = talloc_stackframe();
1291         struct cli_state *cli = NULL;
1292         struct rpc_pipe_client *netlogon_pipe = NULL;
1293         struct netlogon_creds_cli_context *netlogon_creds = NULL;
1294         struct netlogon_creds_CredentialState *creds = NULL;
1295         uint32_t netlogon_flags = 0;
1296         enum netr_SchannelType sec_chan_type = 0;
1297         NTSTATUS status;
1298         char *machine_password = NULL;
1299         const char *machine_name = NULL;
1300         const char *machine_account = NULL;
1301         int flags = 0;
1302         struct samr_Password current_nt_hash;
1303         struct samr_Password *previous_nt_hash = NULL;
1304         bool ok;
1305
1306         if (!dc_name) {
1307                 TALLOC_FREE(frame);
1308                 return NT_STATUS_INVALID_PARAMETER;
1309         }
1310
1311         if (!secrets_init()) {
1312                 TALLOC_FREE(frame);
1313                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1314         }
1315
1316         ok = get_trust_pw_clear(netbios_domain_name,
1317                                 &machine_password,
1318                                 &machine_name,
1319                                 &sec_chan_type);
1320         if (!ok) {
1321                 TALLOC_FREE(frame);
1322                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1323         }
1324
1325         machine_account = talloc_asprintf(frame, "%s$", machine_name);
1326         if (machine_account == NULL) {
1327                 SAFE_FREE(machine_password);
1328                 SAFE_FREE(previous_nt_hash);
1329                 TALLOC_FREE(frame);
1330                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1331         }
1332
1333         if (use_kerberos) {
1334                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1335         }
1336
1337         status = cli_full_connection(&cli, NULL,
1338                                      dc_name,
1339                                      NULL, 0,
1340                                      "IPC$", "IPC",
1341                                      machine_account,
1342                                      netbios_domain_name,
1343                                      machine_password,
1344                                      flags,
1345                                      SMB_SIGNING_DEFAULT);
1346
1347         E_md4hash(machine_password, current_nt_hash.hash);
1348         SAFE_FREE(machine_password);
1349
1350         if (!NT_STATUS_IS_OK(status)) {
1351                 status = cli_full_connection(&cli, NULL,
1352                                              dc_name,
1353                                              NULL, 0,
1354                                              "IPC$", "IPC",
1355                                              "",
1356                                              NULL,
1357                                              "",
1358                                              0,
1359                                              SMB_SIGNING_DEFAULT);
1360         }
1361
1362         if (!NT_STATUS_IS_OK(status)) {
1363                 SAFE_FREE(previous_nt_hash);
1364                 TALLOC_FREE(frame);
1365                 return status;
1366         }
1367
1368         status = rpccli_create_netlogon_creds(dc_name,
1369                                               netbios_domain_name,
1370                                               machine_account,
1371                                               sec_chan_type,
1372                                               msg_ctx,
1373                                               frame,
1374                                               &netlogon_creds);
1375         if (!NT_STATUS_IS_OK(status)) {
1376                 SAFE_FREE(previous_nt_hash);
1377                 cli_shutdown(cli);
1378                 TALLOC_FREE(frame);
1379                 return status;
1380         }
1381
1382         status = rpccli_setup_netlogon_creds(cli,
1383                                              netlogon_creds,
1384                                              true, /* force_reauth */
1385                                              current_nt_hash,
1386                                              previous_nt_hash);
1387         SAFE_FREE(previous_nt_hash);
1388         if (!NT_STATUS_IS_OK(status)) {
1389                 DEBUG(0,("connect_to_domain_password_server: "
1390                          "unable to open the domain client session to "
1391                          "machine %s. Flags[0x%08X] Error was : %s.\n",
1392                          dc_name, (unsigned)netlogon_flags,
1393                          nt_errstr(status)));
1394                 cli_shutdown(cli);
1395                 TALLOC_FREE(frame);
1396                 return status;
1397         }
1398
1399         status = netlogon_creds_cli_get(netlogon_creds,
1400                                         talloc_tos(),
1401                                         &creds);
1402         if (!NT_STATUS_IS_OK(status)) {
1403                 cli_shutdown(cli);
1404                 TALLOC_FREE(frame);
1405                 return status;
1406         }
1407         netlogon_flags = creds->negotiate_flags;
1408         TALLOC_FREE(creds);
1409
1410         if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1411                 cli_shutdown(cli);
1412                 TALLOC_FREE(frame);
1413                 return NT_STATUS_OK;
1414         }
1415
1416         status = cli_rpc_pipe_open_schannel_with_key(
1417                 cli, &ndr_table_netlogon, NCACN_NP,
1418                 netbios_domain_name,
1419                 netlogon_creds, &netlogon_pipe);
1420
1421         TALLOC_FREE(netlogon_pipe);
1422
1423         if (!NT_STATUS_IS_OK(status)) {
1424                 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1425                         "on netlogon pipe to server %s for domain %s. "
1426                         "Error was %s\n",
1427                         smbXcli_conn_remote_name(cli->conn),
1428                         netbios_domain_name, nt_errstr(status)));
1429                 cli_shutdown(cli);
1430                 TALLOC_FREE(frame);
1431                 return status;
1432         }
1433
1434         cli_shutdown(cli);
1435         TALLOC_FREE(frame);
1436         return NT_STATUS_OK;
1437 }
1438
1439 /****************************************************************
1440 ****************************************************************/
1441
1442 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1443                                       struct libnet_JoinCtx *r)
1444 {
1445         NTSTATUS status;
1446
1447         status = libnet_join_ok(r->in.msg_ctx,
1448                                 r->out.netbios_domain_name,
1449                                 r->in.dc_name,
1450                                 r->in.use_kerberos);
1451         if (!NT_STATUS_IS_OK(status)) {
1452                 libnet_join_set_error_string(mem_ctx, r,
1453                         "failed to verify domain membership after joining: %s",
1454                         get_friendly_nt_error_msg(status));
1455                 return WERR_SETUP_NOT_JOINED;
1456         }
1457
1458         return WERR_OK;
1459 }
1460
1461 /****************************************************************
1462 ****************************************************************/
1463
1464 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1465                                                     struct libnet_UnjoinCtx *r)
1466 {
1467         if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1468                 return false;
1469         }
1470
1471         if (!secrets_delete_domain_sid(lp_workgroup())) {
1472                 return false;
1473         }
1474
1475         return true;
1476 }
1477
1478 /****************************************************************
1479 ****************************************************************/
1480
1481 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1482                                              struct libnet_UnjoinCtx *r)
1483 {
1484         struct cli_state *cli = NULL;
1485         struct rpc_pipe_client *pipe_hnd = NULL;
1486         struct policy_handle sam_pol, domain_pol, user_pol;
1487         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1488         char *acct_name;
1489         uint32_t user_rid;
1490         struct lsa_String lsa_acct_name;
1491         struct samr_Ids user_rids;
1492         struct samr_Ids name_types;
1493         union samr_UserInfo *info = NULL;
1494         struct dcerpc_binding_handle *b = NULL;
1495
1496         ZERO_STRUCT(sam_pol);
1497         ZERO_STRUCT(domain_pol);
1498         ZERO_STRUCT(user_pol);
1499
1500         status = libnet_join_connect_dc_ipc(r->in.dc_name,
1501                                             r->in.admin_account,
1502                                             r->in.admin_domain,
1503                                             r->in.admin_password,
1504                                             r->in.use_kerberos,
1505                                             &cli);
1506         if (!NT_STATUS_IS_OK(status)) {
1507                 goto done;
1508         }
1509
1510         /* Open the domain */
1511
1512         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1513                                           &pipe_hnd);
1514         if (!NT_STATUS_IS_OK(status)) {
1515                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1516                         nt_errstr(status)));
1517                 goto done;
1518         }
1519
1520         b = pipe_hnd->binding_handle;
1521
1522         status = dcerpc_samr_Connect2(b, mem_ctx,
1523                                       pipe_hnd->desthost,
1524                                       SEC_FLAG_MAXIMUM_ALLOWED,
1525                                       &sam_pol,
1526                                       &result);
1527         if (!NT_STATUS_IS_OK(status)) {
1528                 goto done;
1529         }
1530         if (!NT_STATUS_IS_OK(result)) {
1531                 status = result;
1532                 goto done;
1533         }
1534
1535         status = dcerpc_samr_OpenDomain(b, mem_ctx,
1536                                         &sam_pol,
1537                                         SEC_FLAG_MAXIMUM_ALLOWED,
1538                                         r->in.domain_sid,
1539                                         &domain_pol,
1540                                         &result);
1541         if (!NT_STATUS_IS_OK(status)) {
1542                 goto done;
1543         }
1544         if (!NT_STATUS_IS_OK(result)) {
1545                 status = result;
1546                 goto done;
1547         }
1548
1549         /* Create domain user */
1550
1551         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1552         if (!strlower_m(acct_name)) {
1553                 status = NT_STATUS_INVALID_PARAMETER;
1554                 goto done;
1555         }
1556
1557         init_lsa_String(&lsa_acct_name, acct_name);
1558
1559         status = dcerpc_samr_LookupNames(b, mem_ctx,
1560                                          &domain_pol,
1561                                          1,
1562                                          &lsa_acct_name,
1563                                          &user_rids,
1564                                          &name_types,
1565                                          &result);
1566
1567         if (!NT_STATUS_IS_OK(status)) {
1568                 goto done;
1569         }
1570         if (!NT_STATUS_IS_OK(result)) {
1571                 status = result;
1572                 goto done;
1573         }
1574         if (user_rids.count != 1) {
1575                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1576                 goto done;
1577         }
1578         if (name_types.count != 1) {
1579                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1580                 goto done;
1581         }
1582
1583         if (name_types.ids[0] != SID_NAME_USER) {
1584                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1585                         name_types.ids[0]));
1586                 status = NT_STATUS_INVALID_WORKSTATION;
1587                 goto done;
1588         }
1589
1590         user_rid = user_rids.ids[0];
1591
1592         /* Open handle on user */
1593
1594         status = dcerpc_samr_OpenUser(b, mem_ctx,
1595                                       &domain_pol,
1596                                       SEC_FLAG_MAXIMUM_ALLOWED,
1597                                       user_rid,
1598                                       &user_pol,
1599                                       &result);
1600         if (!NT_STATUS_IS_OK(status)) {
1601                 goto done;
1602         }
1603         if (!NT_STATUS_IS_OK(result)) {
1604                 status = result;
1605                 goto done;
1606         }
1607
1608         /* Get user info */
1609
1610         status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1611                                            &user_pol,
1612                                            16,
1613                                            &info,
1614                                            &result);
1615         if (!NT_STATUS_IS_OK(status)) {
1616                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1617                 goto done;
1618         }
1619         if (!NT_STATUS_IS_OK(result)) {
1620                 status = result;
1621                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1622                 goto done;
1623         }
1624
1625         /* now disable and setuser info */
1626
1627         info->info16.acct_flags |= ACB_DISABLED;
1628
1629         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1630                                          &user_pol,
1631                                          16,
1632                                          info,
1633                                          &result);
1634         if (!NT_STATUS_IS_OK(status)) {
1635                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1636                 goto done;
1637         }
1638         if (!NT_STATUS_IS_OK(result)) {
1639                 status = result;
1640                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1641                 goto done;
1642         }
1643         status = result;
1644         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1645
1646 done:
1647         if (pipe_hnd && b) {
1648                 if (is_valid_policy_hnd(&domain_pol)) {
1649                         dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1650                 }
1651                 if (is_valid_policy_hnd(&sam_pol)) {
1652                         dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1653                 }
1654                 TALLOC_FREE(pipe_hnd);
1655         }
1656
1657         if (cli) {
1658                 cli_shutdown(cli);
1659         }
1660
1661         return status;
1662 }
1663
1664 /****************************************************************
1665 ****************************************************************/
1666
1667 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1668 {
1669         WERROR werr = WERR_OK;
1670         sbcErr err;
1671         struct smbconf_ctx *ctx;
1672
1673         err = smbconf_init_reg(r, &ctx, NULL);
1674         if (!SBC_ERROR_IS_OK(err)) {
1675                 werr = WERR_NO_SUCH_SERVICE;
1676                 goto done;
1677         }
1678
1679         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1680
1681                 err = smbconf_set_global_parameter(ctx, "security", "user");
1682                 if (!SBC_ERROR_IS_OK(err)) {
1683                         werr = WERR_NO_SUCH_SERVICE;
1684                         goto done;
1685                 }
1686
1687                 err = smbconf_set_global_parameter(ctx, "workgroup",
1688                                                    r->in.domain_name);
1689                 if (!SBC_ERROR_IS_OK(err)) {
1690                         werr = WERR_NO_SUCH_SERVICE;
1691                         goto done;
1692                 }
1693
1694                 smbconf_delete_global_parameter(ctx, "realm");
1695                 goto done;
1696         }
1697
1698         err = smbconf_set_global_parameter(ctx, "security", "domain");
1699         if (!SBC_ERROR_IS_OK(err)) {
1700                 werr = WERR_NO_SUCH_SERVICE;
1701                 goto done;
1702         }
1703
1704         err = smbconf_set_global_parameter(ctx, "workgroup",
1705                                            r->out.netbios_domain_name);
1706         if (!SBC_ERROR_IS_OK(err)) {
1707                 werr = WERR_NO_SUCH_SERVICE;
1708                 goto done;
1709         }
1710
1711         if (r->out.domain_is_ad) {
1712                 err = smbconf_set_global_parameter(ctx, "security", "ads");
1713                 if (!SBC_ERROR_IS_OK(err)) {
1714                         werr = WERR_NO_SUCH_SERVICE;
1715                         goto done;
1716                 }
1717
1718                 err = smbconf_set_global_parameter(ctx, "realm",
1719                                                    r->out.dns_domain_name);
1720                 if (!SBC_ERROR_IS_OK(err)) {
1721                         werr = WERR_NO_SUCH_SERVICE;
1722                         goto done;
1723                 }
1724         }
1725
1726  done:
1727         smbconf_shutdown(ctx);
1728         return werr;
1729 }
1730
1731 /****************************************************************
1732 ****************************************************************/
1733
1734 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1735 {
1736         WERROR werr = WERR_OK;
1737         sbcErr err;
1738         struct smbconf_ctx *ctx;
1739
1740         err = smbconf_init_reg(r, &ctx, NULL);
1741         if (!SBC_ERROR_IS_OK(err)) {
1742                 werr = WERR_NO_SUCH_SERVICE;
1743                 goto done;
1744         }
1745
1746         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1747
1748                 err = smbconf_set_global_parameter(ctx, "security", "user");
1749                 if (!SBC_ERROR_IS_OK(err)) {
1750                         werr = WERR_NO_SUCH_SERVICE;
1751                         goto done;
1752                 }
1753
1754                 err = smbconf_delete_global_parameter(ctx, "workgroup");
1755                 if (!SBC_ERROR_IS_OK(err)) {
1756                         werr = WERR_NO_SUCH_SERVICE;
1757                         goto done;
1758                 }
1759
1760                 smbconf_delete_global_parameter(ctx, "realm");
1761         }
1762
1763  done:
1764         smbconf_shutdown(ctx);
1765         return werr;
1766 }
1767
1768 /****************************************************************
1769 ****************************************************************/
1770
1771 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1772 {
1773         WERROR werr;
1774
1775         if (!W_ERROR_IS_OK(r->out.result)) {
1776                 return r->out.result;
1777         }
1778
1779         if (!r->in.modify_config) {
1780                 return WERR_OK;
1781         }
1782
1783         werr = do_join_modify_vals_config(r);
1784         if (!W_ERROR_IS_OK(werr)) {
1785                 return werr;
1786         }
1787
1788         lp_load_global(get_dyn_CONFIGFILE());
1789
1790         r->out.modified_config = true;
1791         r->out.result = werr;
1792
1793         return werr;
1794 }
1795
1796 /****************************************************************
1797 ****************************************************************/
1798
1799 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1800 {
1801         WERROR werr;
1802
1803         if (!W_ERROR_IS_OK(r->out.result)) {
1804                 return r->out.result;
1805         }
1806
1807         if (!r->in.modify_config) {
1808                 return WERR_OK;
1809         }
1810
1811         werr = do_unjoin_modify_vals_config(r);
1812         if (!W_ERROR_IS_OK(werr)) {
1813                 return werr;
1814         }
1815
1816         lp_load_global(get_dyn_CONFIGFILE());
1817
1818         r->out.modified_config = true;
1819         r->out.result = werr;
1820
1821         return werr;
1822 }
1823
1824 /****************************************************************
1825 ****************************************************************/
1826
1827 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1828                                    const char *domain_str,
1829                                    const char **domain_p,
1830                                    const char **dc_p)
1831 {
1832         char *domain = NULL;
1833         char *dc = NULL;
1834         const char *p = NULL;
1835
1836         if (!domain_str || !domain_p || !dc_p) {
1837                 return false;
1838         }
1839
1840         p = strchr_m(domain_str, '\\');
1841
1842         if (p != NULL) {
1843                 domain = talloc_strndup(mem_ctx, domain_str,
1844                                          PTR_DIFF(p, domain_str));
1845                 dc = talloc_strdup(mem_ctx, p+1);
1846                 if (!dc) {
1847                         return false;
1848                 }
1849         } else {
1850                 domain = talloc_strdup(mem_ctx, domain_str);
1851                 dc = NULL;
1852         }
1853         if (!domain) {
1854                 return false;
1855         }
1856
1857         *domain_p = domain;
1858
1859         if (!*dc_p && dc) {
1860                 *dc_p = dc;
1861         }
1862
1863         return true;
1864 }
1865
1866 /****************************************************************
1867 ****************************************************************/
1868
1869 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1870                                          struct libnet_JoinCtx *r)
1871 {
1872         if (!r->in.domain_name) {
1873                 libnet_join_set_error_string(mem_ctx, r,
1874                         "No domain name defined");
1875                 return WERR_INVALID_PARAM;
1876         }
1877
1878         if (strlen(r->in.machine_name) > 15) {
1879                 libnet_join_set_error_string(mem_ctx, r,
1880                         "Our netbios name can be at most 15 chars long, "
1881                          "\"%s\" is %u chars long\n",
1882                          r->in.machine_name,
1883                          (unsigned int)strlen(r->in.machine_name));
1884                 return WERR_INVALID_PARAM;
1885         }
1886
1887         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1888                                     &r->in.domain_name,
1889                                     &r->in.dc_name)) {
1890                 libnet_join_set_error_string(mem_ctx, r,
1891                         "Failed to parse domain name");
1892                 return WERR_INVALID_PARAM;
1893         }
1894
1895         if (IS_DC) {
1896                 return WERR_SETUP_DOMAIN_CONTROLLER;
1897         }
1898
1899         if (!r->in.admin_domain) {
1900                 char *admin_domain = NULL;
1901                 char *admin_account = NULL;
1902                 split_domain_user(mem_ctx,
1903                                   r->in.admin_account,
1904                                   &admin_domain,
1905                                   &admin_account);
1906                 r->in.admin_domain = admin_domain;
1907                 r->in.admin_account = admin_account;
1908         }
1909
1910         if (!secrets_init()) {
1911                 libnet_join_set_error_string(mem_ctx, r,
1912                         "Unable to open secrets database");
1913                 return WERR_CAN_NOT_COMPLETE;
1914         }
1915
1916         return WERR_OK;
1917 }
1918
1919 /****************************************************************
1920 ****************************************************************/
1921
1922 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1923 {
1924         NTSTATUS status;
1925
1926         /* Try adding dom admins to builtin\admins. Only log failures. */
1927         status = create_builtin_administrators(domain_sid);
1928         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1929                 DEBUG(10,("Unable to auto-add domain administrators to "
1930                           "BUILTIN\\Administrators during join because "
1931                           "winbindd must be running.\n"));
1932         } else if (!NT_STATUS_IS_OK(status)) {
1933                 DEBUG(5, ("Failed to auto-add domain administrators to "
1934                           "BUILTIN\\Administrators during join: %s\n",
1935                           nt_errstr(status)));
1936         }
1937
1938         /* Try adding dom users to builtin\users. Only log failures. */
1939         status = create_builtin_users(domain_sid);
1940         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1941                 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1942                           "during join because winbindd must be running.\n"));
1943         } else if (!NT_STATUS_IS_OK(status)) {
1944                 DEBUG(5, ("Failed to auto-add domain administrators to "
1945                           "BUILTIN\\Administrators during join: %s\n",
1946                           nt_errstr(status)));
1947         }
1948 }
1949
1950 /****************************************************************
1951 ****************************************************************/
1952
1953 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1954                                           struct libnet_JoinCtx *r)
1955 {
1956         WERROR werr;
1957
1958         if (!W_ERROR_IS_OK(r->out.result)) {
1959                 return r->out.result;
1960         }
1961
1962         werr = do_JoinConfig(r);
1963         if (!W_ERROR_IS_OK(werr)) {
1964                 return werr;
1965         }
1966
1967         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1968                 return WERR_OK;
1969         }
1970
1971         saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1972         if (r->out.dns_domain_name) {
1973                 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1974         }
1975
1976 #ifdef HAVE_ADS
1977         if (r->out.domain_is_ad &&
1978             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1979                 ADS_STATUS ads_status;
1980
1981                 ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
1982                 if (!ADS_ERR_OK(ads_status)) {
1983                         return WERR_GENERAL_FAILURE;
1984                 }
1985         }
1986 #endif /* HAVE_ADS */
1987
1988         libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1989
1990         return WERR_OK;
1991 }
1992
1993 /****************************************************************
1994 ****************************************************************/
1995
1996 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1997 {
1998         if (r->in.ads) {
1999                 ads_destroy(&r->in.ads);
2000         }
2001
2002         return 0;
2003 }
2004
2005 /****************************************************************
2006 ****************************************************************/
2007
2008 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2009 {
2010         if (r->in.ads) {
2011                 ads_destroy(&r->in.ads);
2012         }
2013
2014         return 0;
2015 }
2016
2017 /****************************************************************
2018 ****************************************************************/
2019
2020 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2021                            struct libnet_JoinCtx **r)
2022 {
2023         struct libnet_JoinCtx *ctx;
2024
2025         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2026         if (!ctx) {
2027                 return WERR_NOMEM;
2028         }
2029
2030         talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2031
2032         ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2033         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2034
2035         ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2036
2037         *r = ctx;
2038
2039         return WERR_OK;
2040 }
2041
2042 /****************************************************************
2043 ****************************************************************/
2044
2045 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2046                              struct libnet_UnjoinCtx **r)
2047 {
2048         struct libnet_UnjoinCtx *ctx;
2049
2050         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2051         if (!ctx) {
2052                 return WERR_NOMEM;
2053         }
2054
2055         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2056
2057         ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2058         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2059
2060         *r = ctx;
2061
2062         return WERR_OK;
2063 }
2064
2065 /****************************************************************
2066 ****************************************************************/
2067
2068 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2069                                        struct libnet_JoinCtx *r)
2070 {
2071         bool valid_security = false;
2072         bool valid_workgroup = false;
2073         bool valid_realm = false;
2074
2075         /* check if configuration is already set correctly */
2076
2077         valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2078
2079         switch (r->out.domain_is_ad) {
2080                 case false:
2081                         valid_security = (lp_security() == SEC_DOMAIN);
2082                         if (valid_workgroup && valid_security) {
2083                                 /* nothing to be done */
2084                                 return WERR_OK;
2085                         }
2086                         break;
2087                 case true:
2088                         valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2089                         switch (lp_security()) {
2090                         case SEC_DOMAIN:
2091                         case SEC_ADS:
2092                                 valid_security = true;
2093                         }
2094
2095                         if (valid_workgroup && valid_realm && valid_security) {
2096                                 /* nothing to be done */
2097                                 return WERR_OK;
2098                         }
2099                         break;
2100         }
2101
2102         /* check if we are supposed to manipulate configuration */
2103
2104         if (!r->in.modify_config) {
2105
2106                 char *wrong_conf = talloc_strdup(mem_ctx, "");
2107
2108                 if (!valid_workgroup) {
2109                         wrong_conf = talloc_asprintf_append(wrong_conf,
2110                                 "\"workgroup\" set to '%s', should be '%s'",
2111                                 lp_workgroup(), r->out.netbios_domain_name);
2112                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2113                 }
2114
2115                 if (!valid_realm) {
2116                         wrong_conf = talloc_asprintf_append(wrong_conf,
2117                                 "\"realm\" set to '%s', should be '%s'",
2118                                 lp_realm(), r->out.dns_domain_name);
2119                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2120                 }
2121
2122                 if (!valid_security) {
2123                         const char *sec = NULL;
2124                         switch (lp_security()) {
2125                         case SEC_USER:  sec = "user"; break;
2126                         case SEC_DOMAIN: sec = "domain"; break;
2127                         case SEC_ADS: sec = "ads"; break;
2128                         }
2129                         wrong_conf = talloc_asprintf_append(wrong_conf,
2130                                 "\"security\" set to '%s', should be %s",
2131                                 sec, r->out.domain_is_ad ?
2132                                 "either 'domain' or 'ads'" : "'domain'");
2133                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2134                 }
2135
2136                 libnet_join_set_error_string(mem_ctx, r,
2137                         "Invalid configuration (%s) and configuration modification "
2138                         "was not requested", wrong_conf);
2139                 return WERR_CAN_NOT_COMPLETE;
2140         }
2141
2142         /* check if we are able to manipulate configuration */
2143
2144         if (!lp_config_backend_is_registry()) {
2145                 libnet_join_set_error_string(mem_ctx, r,
2146                         "Configuration manipulation requested but not "
2147                         "supported by backend");
2148                 return WERR_NOT_SUPPORTED;
2149         }
2150
2151         return WERR_OK;
2152 }
2153
2154 /****************************************************************
2155 ****************************************************************/
2156
2157 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2158                                 struct libnet_JoinCtx *r)
2159 {
2160         NTSTATUS status;
2161         WERROR werr;
2162         struct cli_state *cli = NULL;
2163 #ifdef HAVE_ADS
2164         ADS_STATUS ads_status;
2165 #endif /* HAVE_ADS */
2166
2167         if (!r->in.dc_name) {
2168                 struct netr_DsRGetDCNameInfo *info;
2169                 const char *dc;
2170                 status = dsgetdcname(mem_ctx,
2171                                      r->in.msg_ctx,
2172                                      r->in.domain_name,
2173                                      NULL,
2174                                      NULL,
2175                                      DS_FORCE_REDISCOVERY |
2176                                      DS_DIRECTORY_SERVICE_REQUIRED |
2177                                      DS_WRITABLE_REQUIRED |
2178                                      DS_RETURN_DNS_NAME,
2179                                      &info);
2180                 if (!NT_STATUS_IS_OK(status)) {
2181                         libnet_join_set_error_string(mem_ctx, r,
2182                                 "failed to find DC for domain %s",
2183                                 r->in.domain_name,
2184                                 get_friendly_nt_error_msg(status));
2185                         return WERR_DCNOTFOUND;
2186                 }
2187
2188                 dc = strip_hostname(info->dc_unc);
2189                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2190                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2191         }
2192
2193         status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2194         if (!NT_STATUS_IS_OK(status)) {
2195                 libnet_join_set_error_string(mem_ctx, r,
2196                         "failed to lookup DC info for domain '%s' over rpc: %s",
2197                         r->in.domain_name, get_friendly_nt_error_msg(status));
2198                 return ntstatus_to_werror(status);
2199         }
2200
2201         werr = libnet_join_check_config(mem_ctx, r);
2202         if (!W_ERROR_IS_OK(werr)) {
2203                 goto done;
2204         }
2205
2206 #ifdef HAVE_ADS
2207
2208         create_local_private_krb5_conf_for_domain(
2209                 r->out.dns_domain_name, r->out.netbios_domain_name,
2210                 NULL, smbXcli_conn_remote_sockaddr(cli->conn));
2211
2212         if (r->out.domain_is_ad && r->in.account_ou &&
2213             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2214
2215                 ads_status = libnet_join_connect_ads(mem_ctx, r);
2216                 if (!ADS_ERR_OK(ads_status)) {
2217                         return WERR_DEFAULT_JOIN_REQUIRED;
2218                 }
2219
2220                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2221                 if (!ADS_ERR_OK(ads_status)) {
2222                         libnet_join_set_error_string(mem_ctx, r,
2223                                 "failed to precreate account in ou %s: %s",
2224                                 r->in.account_ou,
2225                                 ads_errstr(ads_status));
2226                         return WERR_DEFAULT_JOIN_REQUIRED;
2227                 }
2228
2229                 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2230         }
2231 #endif /* HAVE_ADS */
2232
2233         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2234             (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2235                 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2236         } else {
2237                 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2238         }
2239         if (!NT_STATUS_IS_OK(status)) {
2240                 libnet_join_set_error_string(mem_ctx, r,
2241                         "failed to join domain '%s' over rpc: %s",
2242                         r->in.domain_name, get_friendly_nt_error_msg(status));
2243                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2244                         return WERR_SETUP_ALREADY_JOINED;
2245                 }
2246                 werr = ntstatus_to_werror(status);
2247                 goto done;
2248         }
2249
2250         if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2251                 werr = WERR_SETUP_NOT_JOINED;
2252                 goto done;
2253         }
2254
2255         werr = WERR_OK;
2256
2257  done:
2258         if (cli) {
2259                 cli_shutdown(cli);
2260         }
2261
2262         return werr;
2263 }
2264
2265 /****************************************************************
2266 ****************************************************************/
2267
2268 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2269                                    struct libnet_JoinCtx *r)
2270 {
2271         WERROR werr;
2272         struct libnet_UnjoinCtx *u = NULL;
2273
2274         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2275         if (!W_ERROR_IS_OK(werr)) {
2276                 return werr;
2277         }
2278
2279         u->in.debug             = r->in.debug;
2280         u->in.dc_name           = r->in.dc_name;
2281         u->in.domain_name       = r->in.domain_name;
2282         u->in.admin_account     = r->in.admin_account;
2283         u->in.admin_password    = r->in.admin_password;
2284         u->in.modify_config     = r->in.modify_config;
2285         u->in.use_kerberos      = r->in.use_kerberos;
2286         u->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2287                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2288
2289         werr = libnet_Unjoin(mem_ctx, u);
2290         TALLOC_FREE(u);
2291
2292         return werr;
2293 }
2294
2295 /****************************************************************
2296 ****************************************************************/
2297
2298 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2299                    struct libnet_JoinCtx *r)
2300 {
2301         WERROR werr;
2302
2303         if (r->in.debug) {
2304                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2305         }
2306
2307         ZERO_STRUCT(r->out);
2308
2309         werr = libnet_join_pre_processing(mem_ctx, r);
2310         if (!W_ERROR_IS_OK(werr)) {
2311                 goto done;
2312         }
2313
2314         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2315                 werr = libnet_DomainJoin(mem_ctx, r);
2316                 if (!W_ERROR_IS_OK(werr)) {
2317                         goto done;
2318                 }
2319         }
2320
2321         werr = libnet_join_post_processing(mem_ctx, r);
2322         if (!W_ERROR_IS_OK(werr)) {
2323                 goto done;
2324         }
2325
2326         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2327                 werr = libnet_join_post_verify(mem_ctx, r);
2328                 if (!W_ERROR_IS_OK(werr)) {
2329                         libnet_join_rollback(mem_ctx, r);
2330                 }
2331         }
2332
2333  done:
2334         r->out.result = werr;
2335
2336         if (r->in.debug) {
2337                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2338         }
2339         return werr;
2340 }
2341
2342 /****************************************************************
2343 ****************************************************************/
2344
2345 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2346                                   struct libnet_UnjoinCtx *r)
2347 {
2348         NTSTATUS status;
2349
2350         if (!r->in.domain_sid) {
2351                 struct dom_sid sid;
2352                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2353                         libnet_unjoin_set_error_string(mem_ctx, r,
2354                                 "Unable to fetch domain sid: are we joined?");
2355                         return WERR_SETUP_NOT_JOINED;
2356                 }
2357                 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2358                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2359         }
2360
2361         if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && 
2362             !r->in.delete_machine_account) {
2363                 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2364                 return WERR_OK;
2365         }
2366
2367         if (!r->in.dc_name) {
2368                 struct netr_DsRGetDCNameInfo *info;
2369                 const char *dc;
2370                 status = dsgetdcname(mem_ctx,
2371                                      r->in.msg_ctx,
2372                                      r->in.domain_name,
2373                                      NULL,
2374                                      NULL,
2375                                      DS_DIRECTORY_SERVICE_REQUIRED |
2376                                      DS_WRITABLE_REQUIRED |
2377                                      DS_RETURN_DNS_NAME,
2378                                      &info);
2379                 if (!NT_STATUS_IS_OK(status)) {
2380                         libnet_unjoin_set_error_string(mem_ctx, r,
2381                                 "failed to find DC for domain %s",
2382                                 r->in.domain_name,
2383                                 get_friendly_nt_error_msg(status));
2384                         return WERR_DCNOTFOUND;
2385                 }
2386
2387                 dc = strip_hostname(info->dc_unc);
2388                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2389                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2390         }
2391
2392 #ifdef HAVE_ADS
2393         /* for net ads leave, try to delete the account.  If it works, 
2394            no sense in disabling.  If it fails, we can still try to 
2395            disable it. jmcd */
2396
2397         if (r->in.delete_machine_account) {
2398                 ADS_STATUS ads_status;
2399                 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2400                 if (ADS_ERR_OK(ads_status)) {
2401                         /* dirty hack */
2402                         r->out.dns_domain_name = 
2403                                 talloc_strdup(mem_ctx,
2404                                               r->in.ads->server.realm);
2405                         ads_status = 
2406                                 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2407                 }
2408                 if (!ADS_ERR_OK(ads_status)) {
2409                         libnet_unjoin_set_error_string(mem_ctx, r,
2410                                 "failed to remove machine account from AD: %s",
2411                                 ads_errstr(ads_status));
2412                 } else {
2413                         r->out.deleted_machine_account = true;
2414                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2415                         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2416                         return WERR_OK;
2417                 }
2418         }
2419 #endif /* HAVE_ADS */
2420
2421         /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means 
2422            "disable".  */
2423         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2424                 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2425                 if (!NT_STATUS_IS_OK(status)) {
2426                         libnet_unjoin_set_error_string(mem_ctx, r,
2427                                 "failed to disable machine account via rpc: %s",
2428                                 get_friendly_nt_error_msg(status));
2429                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2430                                 return WERR_SETUP_NOT_JOINED;
2431                         }
2432                         return ntstatus_to_werror(status);
2433                 }
2434
2435                 r->out.disabled_machine_account = true;
2436         }
2437
2438         /* If disable succeeded or was not requested at all, we 
2439            should be getting rid of our end of things */
2440
2441         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2442
2443         return WERR_OK;
2444 }
2445
2446 /****************************************************************
2447 ****************************************************************/
2448
2449 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2450                                            struct libnet_UnjoinCtx *r)
2451 {
2452         if (!r->in.domain_name) {
2453                 libnet_unjoin_set_error_string(mem_ctx, r,
2454                         "No domain name defined");
2455                 return WERR_INVALID_PARAM;
2456         }
2457
2458         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2459                                     &r->in.domain_name,
2460                                     &r->in.dc_name)) {
2461                 libnet_unjoin_set_error_string(mem_ctx, r,
2462                         "Failed to parse domain name");
2463                 return WERR_INVALID_PARAM;
2464         }
2465
2466         if (IS_DC) {
2467                 return WERR_SETUP_DOMAIN_CONTROLLER;
2468         }
2469
2470         if (!r->in.admin_domain) {
2471                 char *admin_domain = NULL;
2472                 char *admin_account = NULL;
2473                 split_domain_user(mem_ctx,
2474                                   r->in.admin_account,
2475                                   &admin_domain,
2476                                   &admin_account);
2477                 r->in.admin_domain = admin_domain;
2478                 r->in.admin_account = admin_account;
2479         }
2480
2481         if (!secrets_init()) {
2482                 libnet_unjoin_set_error_string(mem_ctx, r,
2483                         "Unable to open secrets database");
2484                 return WERR_CAN_NOT_COMPLETE;
2485         }
2486
2487         return WERR_OK;
2488 }
2489
2490 /****************************************************************
2491 ****************************************************************/
2492
2493 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2494                                             struct libnet_UnjoinCtx *r)
2495 {
2496         saf_delete(r->out.netbios_domain_name);
2497         saf_delete(r->out.dns_domain_name);
2498
2499         return libnet_unjoin_config(r);
2500 }
2501
2502 /****************************************************************
2503 ****************************************************************/
2504
2505 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2506                      struct libnet_UnjoinCtx *r)
2507 {
2508         WERROR werr;
2509
2510         if (r->in.debug) {
2511                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2512         }
2513
2514         werr = libnet_unjoin_pre_processing(mem_ctx, r);
2515         if (!W_ERROR_IS_OK(werr)) {
2516                 goto done;
2517         }
2518
2519         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2520                 werr = libnet_DomainUnjoin(mem_ctx, r);
2521                 if (!W_ERROR_IS_OK(werr)) {
2522                         libnet_unjoin_config(r);
2523                         goto done;
2524                 }
2525         }
2526
2527         werr = libnet_unjoin_post_processing(mem_ctx, r);
2528         if (!W_ERROR_IS_OK(werr)) {
2529                 goto done;
2530         }
2531
2532  done:
2533         r->out.result = werr;
2534
2535         if (r->in.debug) {
2536                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2537         }
2538
2539         return werr;
2540 }