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