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