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