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