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