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