ads_struct
[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 = ENC_CRC32 |
2365                                            ENC_RSA_MD5 |
2366                                            ENC_RC4_HMAC_MD5;
2367 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
2368         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2369 #endif
2370 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
2371         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2372 #endif
2373
2374         *r = ctx;
2375
2376         return WERR_OK;
2377 }
2378
2379 /****************************************************************
2380 ****************************************************************/
2381
2382 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2383                              struct libnet_UnjoinCtx **r)
2384 {
2385         struct libnet_UnjoinCtx *ctx;
2386
2387         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2388         if (!ctx) {
2389                 return WERR_NOT_ENOUGH_MEMORY;
2390         }
2391
2392         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2393
2394         ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2395         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2396
2397         *r = ctx;
2398
2399         return WERR_OK;
2400 }
2401
2402 /****************************************************************
2403 ****************************************************************/
2404
2405 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2406                                        struct libnet_JoinCtx *r)
2407 {
2408         bool valid_security = false;
2409         bool valid_workgroup = false;
2410         bool valid_realm = false;
2411         bool ignored_realm = false;
2412
2413         /* check if configuration is already set correctly */
2414
2415         valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2416
2417         switch (r->out.domain_is_ad) {
2418                 case false:
2419                         valid_security = (lp_security() == SEC_DOMAIN)
2420                                 || (lp_server_role() == ROLE_DOMAIN_PDC)
2421                                 || (lp_server_role() == ROLE_DOMAIN_BDC);
2422                         if (valid_workgroup && valid_security) {
2423                                 /* nothing to be done */
2424                                 return WERR_OK;
2425                         }
2426                         break;
2427                 case true:
2428                         valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2429                         switch (lp_security()) {
2430                         case SEC_DOMAIN:
2431                                 if (!valid_realm && lp_winbind_rpc_only()) {
2432                                         valid_realm = true;
2433                                         ignored_realm = true;
2434                                 }
2435
2436                                 FALL_THROUGH;
2437                         case SEC_ADS:
2438                                 valid_security = true;
2439                         }
2440
2441                         if (valid_workgroup && valid_realm && valid_security) {
2442                                 if (ignored_realm && !r->in.modify_config)
2443                                 {
2444                                         libnet_join_set_error_string(mem_ctx, r,
2445                                                 "Warning: ignoring realm when "
2446                                                 "joining AD domain with "
2447                                                 "'security=domain' and "
2448                                                 "'winbind rpc only = yes'. "
2449                                                 "(realm set to '%s', "
2450                                                 "should be '%s').", lp_realm(),
2451                                                 r->out.dns_domain_name);
2452                                 }
2453                                 /* nothing to be done */
2454                                 return WERR_OK;
2455                         }
2456                         break;
2457         }
2458
2459         /* check if we are supposed to manipulate configuration */
2460
2461         if (!r->in.modify_config) {
2462
2463                 char *wrong_conf = talloc_strdup(mem_ctx, "");
2464
2465                 if (!valid_workgroup) {
2466                         wrong_conf = talloc_asprintf_append(wrong_conf,
2467                                 "\"workgroup\" set to '%s', should be '%s'",
2468                                 lp_workgroup(), r->out.netbios_domain_name);
2469                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2470                 }
2471
2472                 if (!valid_realm) {
2473                         wrong_conf = talloc_asprintf_append(wrong_conf,
2474                                 "\"realm\" set to '%s', should be '%s'",
2475                                 lp_realm(), r->out.dns_domain_name);
2476                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2477                 }
2478
2479                 if (!valid_security) {
2480                         const char *sec = NULL;
2481                         switch (lp_security()) {
2482                         case SEC_USER:  sec = "user"; break;
2483                         case SEC_DOMAIN: sec = "domain"; break;
2484                         case SEC_ADS: sec = "ads"; break;
2485                         }
2486                         wrong_conf = talloc_asprintf_append(wrong_conf,
2487                                 "\"security\" set to '%s', should be %s",
2488                                 sec, r->out.domain_is_ad ?
2489                                 "either 'domain' or 'ads'" : "'domain'");
2490                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2491                 }
2492
2493                 libnet_join_set_error_string(mem_ctx, r,
2494                         "Invalid configuration (%s) and configuration modification "
2495                         "was not requested", wrong_conf);
2496                 return WERR_CAN_NOT_COMPLETE;
2497         }
2498
2499         /* check if we are able to manipulate configuration */
2500
2501         if (!lp_config_backend_is_registry()) {
2502                 libnet_join_set_error_string(mem_ctx, r,
2503                         "Configuration manipulation requested but not "
2504                         "supported by backend");
2505                 return WERR_NOT_SUPPORTED;
2506         }
2507
2508         return WERR_OK;
2509 }
2510
2511 /****************************************************************
2512 ****************************************************************/
2513
2514 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2515                                 struct libnet_JoinCtx *r)
2516 {
2517         NTSTATUS status;
2518         WERROR werr;
2519         struct cli_state *cli = NULL;
2520 #ifdef HAVE_ADS
2521         ADS_STATUS ads_status;
2522 #endif /* HAVE_ADS */
2523         const char *pre_connect_realm = NULL;
2524         const char *numeric_dcip = NULL;
2525         const char *sitename = NULL;
2526
2527         /* Before contacting a DC, we can securely know
2528          * the realm only if the user specifies it.
2529          */
2530         if (r->in.use_kerberos &&
2531             r->in.domain_name_type == JoinDomNameTypeDNS) {
2532                 pre_connect_realm = r->in.domain_name;
2533         }
2534
2535         if (!r->in.dc_name) {
2536                 struct netr_DsRGetDCNameInfo *info;
2537                 const char *dc;
2538                 uint32_t name_type_flags = 0;
2539                 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2540                         name_type_flags = DS_IS_DNS_NAME;
2541                 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2542                         name_type_flags = DS_IS_FLAT_NAME;
2543                 }
2544                 status = dsgetdcname(mem_ctx,
2545                                      r->in.msg_ctx,
2546                                      r->in.domain_name,
2547                                      NULL,
2548                                      NULL,
2549                                      DS_FORCE_REDISCOVERY |
2550                                      DS_DIRECTORY_SERVICE_REQUIRED |
2551                                      DS_WRITABLE_REQUIRED |
2552                                      DS_RETURN_DNS_NAME |
2553                                      name_type_flags,
2554                                      &info);
2555                 if (!NT_STATUS_IS_OK(status)) {
2556                         libnet_join_set_error_string(mem_ctx, r,
2557                                 "failed to find DC for domain %s - %s",
2558                                 r->in.domain_name,
2559                                 get_friendly_nt_error_msg(status));
2560                         return WERR_NERR_DCNOTFOUND;
2561                 }
2562
2563                 dc = strip_hostname(info->dc_unc);
2564                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2565                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2566
2567                 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2568                     info->dc_address[1] != '\\') {
2569                         DBG_ERR("ill-formed DC address '%s'\n",
2570                                 info->dc_address);
2571                         return WERR_NERR_DCNOTFOUND;
2572                 }
2573
2574                 numeric_dcip = info->dc_address + 2;
2575                 sitename = info->dc_site_name;
2576                 /* info goes out of scope but the memory stays
2577                    allocated on the talloc context */
2578         }
2579
2580         if (pre_connect_realm != NULL) {
2581                 struct sockaddr_storage ss = {0};
2582
2583                 if (numeric_dcip != NULL) {
2584                         if (!interpret_string_addr(&ss, numeric_dcip,
2585                                                    AI_NUMERICHOST)) {
2586                                 DBG_ERR(
2587                                     "cannot parse IP address '%s' of DC '%s'\n",
2588                                     numeric_dcip, r->in.dc_name);
2589                                 return WERR_NERR_DCNOTFOUND;
2590                         }
2591                 } else {
2592                         if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2593                                 DBG_WARNING(
2594                                     "cannot resolve IP address of DC '%s'\n",
2595                                     r->in.dc_name);
2596                                 return WERR_NERR_DCNOTFOUND;
2597                         }
2598                 }
2599
2600                 /* The domain parameter is only used as modifier
2601                  * to krb5.conf file name. .JOIN is is not a valid
2602                  * NetBIOS name so it cannot clash with another domain
2603                  * -- Uri.
2604                  */
2605                 create_local_private_krb5_conf_for_domain(
2606                     pre_connect_realm, ".JOIN", sitename, &ss);
2607         }
2608
2609         status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2610         if (!NT_STATUS_IS_OK(status)) {
2611                 libnet_join_set_error_string(mem_ctx, r,
2612                         "failed to lookup DC info for domain '%s' over rpc: %s",
2613                         r->in.domain_name, get_friendly_nt_error_msg(status));
2614                 return ntstatus_to_werror(status);
2615         }
2616
2617         werr = libnet_join_check_config(mem_ctx, r);
2618         if (!W_ERROR_IS_OK(werr)) {
2619                 goto done;
2620         }
2621
2622 #ifdef HAVE_ADS
2623
2624         if (r->out.domain_is_ad) {
2625                 create_local_private_krb5_conf_for_domain(
2626                         r->out.dns_domain_name, r->out.netbios_domain_name,
2627                         sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2628         }
2629
2630         if (r->out.domain_is_ad &&
2631             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2632
2633                 const char *initial_account_ou = r->in.account_ou;
2634
2635                 /*
2636                  * we want to create the msDS-SupportedEncryptionTypes attribute
2637                  * as early as possible so always try an LDAP create as the user
2638                  * first. We copy r->in.account_ou because it may be changed
2639                  * during the machine pre-creation.
2640                  */
2641
2642                 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2643                 if (!ADS_ERR_OK(ads_status)) {
2644                         return WERR_NERR_DEFAULTJOINREQUIRED;
2645                 }
2646
2647                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2648                 if (ADS_ERR_OK(ads_status)) {
2649
2650                         /*
2651                          * LDAP object create succeeded, now go to the rpc
2652                          * password set routines
2653                          */
2654
2655                         r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2656                         goto rpc_join;
2657                 }
2658
2659                 if (initial_account_ou != NULL) {
2660                         libnet_join_set_error_string(mem_ctx, r,
2661                                 "failed to precreate account in ou %s: %s",
2662                                 r->in.account_ou,
2663                                 ads_errstr(ads_status));
2664                         return WERR_NERR_DEFAULTJOINREQUIRED;
2665                 }
2666
2667                 DEBUG(5, ("failed to precreate account in ou %s: %s",
2668                         r->in.account_ou, ads_errstr(ads_status)));
2669         }
2670  rpc_join:
2671
2672 #endif /* HAVE_ADS */
2673
2674         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2675             (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2676                 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2677         } else {
2678                 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2679         }
2680         if (!NT_STATUS_IS_OK(status)) {
2681                 libnet_join_set_error_string(mem_ctx, r,
2682                         "failed to join domain '%s' over rpc: %s",
2683                         r->in.domain_name, get_friendly_nt_error_msg(status));
2684                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2685                         return WERR_NERR_SETUPALREADYJOINED;
2686                 }
2687                 werr = ntstatus_to_werror(status);
2688                 goto done;
2689         }
2690
2691         werr = WERR_OK;
2692
2693  done:
2694         if (cli) {
2695                 cli_shutdown(cli);
2696         }
2697
2698         return werr;
2699 }
2700
2701 /****************************************************************
2702 ****************************************************************/
2703
2704 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2705                                    struct libnet_JoinCtx *r)
2706 {
2707         WERROR werr;
2708         struct libnet_UnjoinCtx *u = NULL;
2709
2710         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2711         if (!W_ERROR_IS_OK(werr)) {
2712                 return werr;
2713         }
2714
2715         u->in.debug             = r->in.debug;
2716         u->in.dc_name           = r->in.dc_name;
2717         u->in.domain_name       = r->in.domain_name;
2718         u->in.admin_account     = r->in.admin_account;
2719         u->in.admin_password    = r->in.admin_password;
2720         u->in.modify_config     = r->in.modify_config;
2721         u->in.use_kerberos      = r->in.use_kerberos;
2722         u->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2723                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2724
2725         werr = libnet_Unjoin(mem_ctx, u);
2726         TALLOC_FREE(u);
2727
2728         return werr;
2729 }
2730
2731 /****************************************************************
2732 ****************************************************************/
2733
2734 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2735                    struct libnet_JoinCtx *r)
2736 {
2737         WERROR werr;
2738
2739         if (r->in.debug) {
2740                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2741         }
2742
2743         ZERO_STRUCT(r->out);
2744
2745         werr = libnet_join_pre_processing(mem_ctx, r);
2746         if (!W_ERROR_IS_OK(werr)) {
2747                 goto done;
2748         }
2749
2750         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2751                 werr = libnet_DomainJoin(mem_ctx, r);
2752                 if (!W_ERROR_IS_OK(werr)) {
2753                         goto done;
2754                 }
2755         }
2756
2757         werr = libnet_join_post_processing(mem_ctx, r);
2758         if (!W_ERROR_IS_OK(werr)) {
2759                 goto done;
2760         }
2761
2762         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2763                 werr = libnet_join_post_verify(mem_ctx, r);
2764                 if (!W_ERROR_IS_OK(werr)) {
2765                         libnet_join_rollback(mem_ctx, r);
2766                 }
2767         }
2768
2769  done:
2770         r->out.result = werr;
2771
2772         if (r->in.debug) {
2773                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2774         }
2775         return werr;
2776 }
2777
2778 /****************************************************************
2779 ****************************************************************/
2780
2781 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2782                                   struct libnet_UnjoinCtx *r)
2783 {
2784         NTSTATUS status;
2785
2786         if (!r->in.domain_sid) {
2787                 struct dom_sid sid;
2788                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2789                         libnet_unjoin_set_error_string(mem_ctx, r,
2790                                 "Unable to fetch domain sid: are we joined?");
2791                         return WERR_NERR_SETUPNOTJOINED;
2792                 }
2793                 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2794                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2795         }
2796
2797         if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && 
2798             !r->in.delete_machine_account) {
2799                 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2800                 return WERR_OK;
2801         }
2802
2803         if (!r->in.dc_name) {
2804                 struct netr_DsRGetDCNameInfo *info;
2805                 const char *dc;
2806                 status = dsgetdcname(mem_ctx,
2807                                      r->in.msg_ctx,
2808                                      r->in.domain_name,
2809                                      NULL,
2810                                      NULL,
2811                                      DS_DIRECTORY_SERVICE_REQUIRED |
2812                                      DS_WRITABLE_REQUIRED |
2813                                      DS_RETURN_DNS_NAME,
2814                                      &info);
2815                 if (!NT_STATUS_IS_OK(status)) {
2816                         libnet_unjoin_set_error_string(mem_ctx, r,
2817                                 "failed to find DC for domain %s - %s",
2818                                 r->in.domain_name,
2819                                 get_friendly_nt_error_msg(status));
2820                         return WERR_NERR_DCNOTFOUND;
2821                 }
2822
2823                 dc = strip_hostname(info->dc_unc);
2824                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2825                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2826         }
2827
2828 #ifdef HAVE_ADS
2829         /* for net ads leave, try to delete the account.  If it works, 
2830            no sense in disabling.  If it fails, we can still try to 
2831            disable it. jmcd */
2832
2833         if (r->in.delete_machine_account) {
2834                 ADS_STATUS ads_status;
2835                 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2836                 if (ADS_ERR_OK(ads_status)) {
2837                         /* dirty hack */
2838                         r->out.dns_domain_name = 
2839                                 talloc_strdup(mem_ctx,
2840                                               r->in.ads->server.realm);
2841                         ads_status = 
2842                                 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2843                 }
2844                 if (!ADS_ERR_OK(ads_status)) {
2845                         libnet_unjoin_set_error_string(mem_ctx, r,
2846                                 "failed to remove machine account from AD: %s",
2847                                 ads_errstr(ads_status));
2848                 } else {
2849                         r->out.deleted_machine_account = true;
2850                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2851                         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2852                         return WERR_OK;
2853                 }
2854         }
2855 #endif /* HAVE_ADS */
2856
2857         /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means 
2858            "disable".  */
2859         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2860                 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2861                 if (!NT_STATUS_IS_OK(status)) {
2862                         libnet_unjoin_set_error_string(mem_ctx, r,
2863                                 "failed to disable machine account via rpc: %s",
2864                                 get_friendly_nt_error_msg(status));
2865                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2866                                 return WERR_NERR_SETUPNOTJOINED;
2867                         }
2868                         return ntstatus_to_werror(status);
2869                 }
2870
2871                 r->out.dns_domain_name = talloc_strdup(mem_ctx,
2872                                                       r->in.domain_name);
2873                 r->out.disabled_machine_account = true;
2874         }
2875
2876         /* If disable succeeded or was not requested at all, we 
2877            should be getting rid of our end of things */
2878
2879         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2880
2881         return WERR_OK;
2882 }
2883
2884 /****************************************************************
2885 ****************************************************************/
2886
2887 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2888                                            struct libnet_UnjoinCtx *r)
2889 {
2890         if (!r->in.domain_name) {
2891                 libnet_unjoin_set_error_string(mem_ctx, r,
2892                         "No domain name defined");
2893                 return WERR_INVALID_PARAMETER;
2894         }
2895
2896         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2897                                     &r->in.domain_name,
2898                                     &r->in.dc_name)) {
2899                 libnet_unjoin_set_error_string(mem_ctx, r,
2900                         "Failed to parse domain name");
2901                 return WERR_INVALID_PARAMETER;
2902         }
2903
2904         if (IS_DC) {
2905                 return WERR_NERR_SETUPDOMAINCONTROLLER;
2906         }
2907
2908         if (!r->in.admin_domain) {
2909                 char *admin_domain = NULL;
2910                 char *admin_account = NULL;
2911                 bool ok;
2912
2913                 ok = split_domain_user(mem_ctx,
2914                                        r->in.admin_account,
2915                                        &admin_domain,
2916                                        &admin_account);
2917                 if (!ok) {
2918                         return WERR_NOT_ENOUGH_MEMORY;
2919                 }
2920
2921                 if (admin_domain != NULL) {
2922                         r->in.admin_domain = admin_domain;
2923                 } else {
2924                         r->in.admin_domain = r->in.domain_name;
2925                 }
2926                 r->in.admin_account = admin_account;
2927         }
2928
2929         if (!secrets_init()) {
2930                 libnet_unjoin_set_error_string(mem_ctx, r,
2931                         "Unable to open secrets database");
2932                 return WERR_CAN_NOT_COMPLETE;
2933         }
2934
2935         return WERR_OK;
2936 }
2937
2938 /****************************************************************
2939 ****************************************************************/
2940
2941 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2942                                             struct libnet_UnjoinCtx *r)
2943 {
2944         saf_delete(r->out.netbios_domain_name);
2945         saf_delete(r->out.dns_domain_name);
2946
2947         return libnet_unjoin_config(r);
2948 }
2949
2950 /****************************************************************
2951 ****************************************************************/
2952
2953 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2954                      struct libnet_UnjoinCtx *r)
2955 {
2956         WERROR werr;
2957
2958         if (r->in.debug) {
2959                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2960         }
2961
2962         werr = libnet_unjoin_pre_processing(mem_ctx, r);
2963         if (!W_ERROR_IS_OK(werr)) {
2964                 goto done;
2965         }
2966
2967         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2968                 werr = libnet_DomainUnjoin(mem_ctx, r);
2969                 if (!W_ERROR_IS_OK(werr)) {
2970                         libnet_unjoin_config(r);
2971                         goto done;
2972                 }
2973         }
2974
2975         werr = libnet_unjoin_post_processing(mem_ctx, r);
2976         if (!W_ERROR_IS_OK(werr)) {
2977                 goto done;
2978         }
2979
2980  done:
2981         r->out.result = werr;
2982
2983         if (r->in.debug) {
2984                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2985         }
2986
2987         return werr;
2988 }