libsmbconf: add a "path" variable to the conf context.
[jra/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 "libnet/libnet.h"
23
24 /****************************************************************
25 ****************************************************************/
26
27 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
28         do { \
29                 char *str = NULL; \
30                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
31                 DEBUG(1,("libnet_Join:\n%s", str)); \
32                 TALLOC_FREE(str); \
33         } while (0)
34
35 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
36         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
37 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
38         LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
39
40 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
41         do { \
42                 char *str = NULL; \
43                 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
44                 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
45                 TALLOC_FREE(str); \
46         } while (0)
47
48 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
49         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
50 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
51         LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
52
53 #define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
54         if (!W_ERROR_IS_OK(x)) {\
55                 goto done;\
56         }\
57 } while (0)
58
59 /****************************************************************
60 ****************************************************************/
61
62 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
63                                          struct libnet_JoinCtx *r,
64                                          const char *format, ...)
65 {
66         va_list args;
67
68         if (r->out.error_string) {
69                 return;
70         }
71
72         va_start(args, format);
73         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
74         va_end(args);
75 }
76
77 /****************************************************************
78 ****************************************************************/
79
80 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
81                                            struct libnet_UnjoinCtx *r,
82                                            const char *format, ...)
83 {
84         va_list args;
85
86         if (r->out.error_string) {
87                 return;
88         }
89
90         va_start(args, format);
91         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
92         va_end(args);
93 }
94
95 #ifdef WITH_ADS
96
97 /****************************************************************
98 ****************************************************************/
99
100 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
101                                      const char *netbios_domain_name,
102                                      const char *dc_name,
103                                      const char *user_name,
104                                      const char *password,
105                                      ADS_STRUCT **ads)
106 {
107         ADS_STATUS status;
108         ADS_STRUCT *my_ads = NULL;
109
110         my_ads = ads_init(dns_domain_name,
111                           netbios_domain_name,
112                           dc_name);
113         if (!my_ads) {
114                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
115         }
116
117         if (user_name) {
118                 SAFE_FREE(my_ads->auth.user_name);
119                 my_ads->auth.user_name = SMB_STRDUP(user_name);
120         }
121
122         if (password) {
123                 SAFE_FREE(my_ads->auth.password);
124                 my_ads->auth.password = SMB_STRDUP(password);
125         }
126
127         status = ads_connect(my_ads);
128         if (!ADS_ERR_OK(status)) {
129                 ads_destroy(&my_ads);
130                 return status;
131         }
132
133         *ads = my_ads;
134         return ADS_SUCCESS;
135 }
136
137 /****************************************************************
138 ****************************************************************/
139
140 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
141                                           struct libnet_JoinCtx *r)
142 {
143         ADS_STATUS status;
144
145         status = libnet_connect_ads(r->in.domain_name,
146                                     r->in.domain_name,
147                                     r->in.dc_name,
148                                     r->in.admin_account,
149                                     r->in.admin_password,
150                                     &r->in.ads);
151         if (!ADS_ERR_OK(status)) {
152                 libnet_join_set_error_string(mem_ctx, r,
153                         "failed to connect to AD: %s",
154                         ads_errstr(status));
155                 return status;
156         }
157
158         if (!r->out.netbios_domain_name) {
159                 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
160                                                            r->in.ads->server.workgroup);
161                 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
162         }
163
164         if (!r->out.dns_domain_name) {
165                 r->out.dns_domain_name = talloc_strdup(mem_ctx,
166                                                        r->in.ads->config.realm);
167                 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
168         }
169
170         r->out.domain_is_ad = true;
171
172         return ADS_SUCCESS;
173 }
174
175 /****************************************************************
176 ****************************************************************/
177
178 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
179                                             struct libnet_UnjoinCtx *r)
180 {
181         ADS_STATUS status;
182
183         status = libnet_connect_ads(r->in.domain_name,
184                                     r->in.domain_name,
185                                     r->in.dc_name,
186                                     r->in.admin_account,
187                                     r->in.admin_password,
188                                     &r->in.ads);
189         if (!ADS_ERR_OK(status)) {
190                 libnet_unjoin_set_error_string(mem_ctx, r,
191                         "failed to connect to AD: %s",
192                         ads_errstr(status));
193         }
194
195         return status;
196 }
197
198 /****************************************************************
199  join a domain using ADS (LDAP mods)
200 ****************************************************************/
201
202 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
203                                                      struct libnet_JoinCtx *r)
204 {
205         ADS_STATUS status;
206         LDAPMessage *res = NULL;
207         const char *attrs[] = { "dn", NULL };
208         bool moved = false;
209
210         status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
211         if (!ADS_ERR_OK(status)) {
212                 return status;
213         }
214
215         if (ads_count_replies(r->in.ads, res) != 1) {
216                 ads_msgfree(r->in.ads, res);
217                 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
218         }
219
220         ads_msgfree(r->in.ads, res);
221
222         /* Attempt to create the machine account and bail if this fails.
223            Assume that the admin wants exactly what they requested */
224
225         status = ads_create_machine_acct(r->in.ads,
226                                          r->in.machine_name,
227                                          r->in.account_ou);
228
229         if (ADS_ERR_OK(status)) {
230                 DEBUG(1,("machine account creation created\n"));
231                 return status;
232         } else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
233                     (status.err.rc == LDAP_ALREADY_EXISTS)) {
234                 status = ADS_SUCCESS;
235         }
236
237         if (!ADS_ERR_OK(status)) {
238                 DEBUG(1,("machine account creation failed\n"));
239                 return status;
240         }
241
242         status = ads_move_machine_acct(r->in.ads,
243                                        r->in.machine_name,
244                                        r->in.account_ou,
245                                        &moved);
246         if (!ADS_ERR_OK(status)) {
247                 DEBUG(1,("failure to locate/move pre-existing "
248                         "machine account\n"));
249                 return status;
250         }
251
252         DEBUG(1,("The machine account %s the specified OU.\n",
253                 moved ? "was moved into" : "already exists in"));
254
255         return status;
256 }
257
258 /****************************************************************
259 ****************************************************************/
260
261 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
262                                                     struct libnet_UnjoinCtx *r)
263 {
264         ADS_STATUS status;
265
266         if (!r->in.ads) {
267                 return libnet_unjoin_connect_ads(mem_ctx, r);
268         }
269
270         status = ads_leave_realm(r->in.ads, r->in.machine_name);
271         if (!ADS_ERR_OK(status)) {
272                 libnet_unjoin_set_error_string(mem_ctx, r,
273                         "failed to leave realm: %s",
274                         ads_errstr(status));
275                 return status;
276         }
277
278         return ADS_SUCCESS;
279 }
280
281 /****************************************************************
282 ****************************************************************/
283
284 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
285                                                 struct libnet_JoinCtx *r)
286 {
287         ADS_STATUS status;
288         LDAPMessage *res = NULL;
289         char *dn = NULL;
290
291         if (!r->in.machine_name) {
292                 return ADS_ERROR(LDAP_NO_MEMORY);
293         }
294
295         status = ads_find_machine_acct(r->in.ads,
296                                        &res,
297                                        r->in.machine_name);
298         if (!ADS_ERR_OK(status)) {
299                 return status;
300         }
301
302         if (ads_count_replies(r->in.ads, res) != 1) {
303                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
304                 goto done;
305         }
306
307         dn = ads_get_dn(r->in.ads, res);
308         if (!dn) {
309                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
310                 goto done;
311         }
312
313         r->out.dn = talloc_strdup(mem_ctx, dn);
314         if (!r->out.dn) {
315                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
316                 goto done;
317         }
318
319  done:
320         ads_msgfree(r->in.ads, res);
321         ads_memfree(r->in.ads, dn);
322
323         return status;
324 }
325
326 /****************************************************************
327  Set a machines dNSHostName and servicePrincipalName attributes
328 ****************************************************************/
329
330 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
331                                               struct libnet_JoinCtx *r)
332 {
333         ADS_STATUS status;
334         ADS_MODLIST mods;
335         fstring my_fqdn;
336         const char *spn_array[3] = {NULL, NULL, NULL};
337         char *spn = NULL;
338
339         /* Find our DN */
340
341         status = libnet_join_find_machine_acct(mem_ctx, r);
342         if (!ADS_ERR_OK(status)) {
343                 return status;
344         }
345
346         /* Windows only creates HOST/shortname & HOST/fqdn. */
347
348         spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
349         if (!spn) {
350                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
351         }
352         strupper_m(spn);
353         spn_array[0] = spn;
354
355         if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
356             !strequal(my_fqdn, r->in.machine_name)) {
357
358                 strlower_m(my_fqdn);
359                 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
360                 if (!spn) {
361                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
362                 }
363                 spn_array[1] = spn;
364         }
365
366         mods = ads_init_mods(mem_ctx);
367         if (!mods) {
368                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
369         }
370
371         /* fields of primary importance */
372
373         status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
374         if (!ADS_ERR_OK(status)) {
375                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
376         }
377
378         status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
379                                  spn_array);
380         if (!ADS_ERR_OK(status)) {
381                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
382         }
383
384         return ads_gen_mod(r->in.ads, r->out.dn, mods);
385 }
386
387 /****************************************************************
388 ****************************************************************/
389
390 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
391                                               struct libnet_JoinCtx *r)
392 {
393         ADS_STATUS status;
394         ADS_MODLIST mods;
395
396         if (!r->in.create_upn) {
397                 return ADS_SUCCESS;
398         }
399
400         /* Find our DN */
401
402         status = libnet_join_find_machine_acct(mem_ctx, r);
403         if (!ADS_ERR_OK(status)) {
404                 return status;
405         }
406
407         if (!r->in.upn) {
408                 r->in.upn = talloc_asprintf(mem_ctx,
409                                             "host/%s@%s",
410                                             r->in.machine_name,
411                                             r->out.dns_domain_name);
412                 if (!r->in.upn) {
413                         return ADS_ERROR(LDAP_NO_MEMORY);
414                 }
415         }
416
417         /* now do the mods */
418
419         mods = ads_init_mods(mem_ctx);
420         if (!mods) {
421                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
422         }
423
424         /* fields of primary importance */
425
426         status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
427         if (!ADS_ERR_OK(status)) {
428                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
429         }
430
431         return ads_gen_mod(r->in.ads, r->out.dn, mods);
432 }
433
434
435 /****************************************************************
436 ****************************************************************/
437
438 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
439                                                 struct libnet_JoinCtx *r)
440 {
441         ADS_STATUS status;
442         ADS_MODLIST mods;
443         char *os_sp = NULL;
444
445         if (!r->in.os_name || !r->in.os_version ) {
446                 return ADS_SUCCESS;
447         }
448
449         /* Find our DN */
450
451         status = libnet_join_find_machine_acct(mem_ctx, r);
452         if (!ADS_ERR_OK(status)) {
453                 return status;
454         }
455
456         /* now do the mods */
457
458         mods = ads_init_mods(mem_ctx);
459         if (!mods) {
460                 return ADS_ERROR(LDAP_NO_MEMORY);
461         }
462
463         os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
464         if (!os_sp) {
465                 return ADS_ERROR(LDAP_NO_MEMORY);
466         }
467
468         /* fields of primary importance */
469
470         status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
471                              r->in.os_name);
472         if (!ADS_ERR_OK(status)) {
473                 return status;
474         }
475
476         status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
477                              r->in.os_version);
478         if (!ADS_ERR_OK(status)) {
479                 return status;
480         }
481
482         status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
483                              os_sp);
484         if (!ADS_ERR_OK(status)) {
485                 return status;
486         }
487
488         return ads_gen_mod(r->in.ads, r->out.dn, mods);
489 }
490
491 /****************************************************************
492 ****************************************************************/
493
494 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
495                                       struct libnet_JoinCtx *r)
496 {
497         if (!lp_use_kerberos_keytab()) {
498                 return true;
499         }
500
501         if (!ads_keytab_create_default(r->in.ads)) {
502                 return false;
503         }
504
505         return true;
506 }
507
508 /****************************************************************
509 ****************************************************************/
510
511 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
512                                                  struct libnet_JoinCtx *r)
513 {
514         uint32_t domain_func;
515         ADS_STATUS status;
516         const char *salt = NULL;
517         char *std_salt = NULL;
518
519         status = ads_domain_func_level(r->in.ads, &domain_func);
520         if (!ADS_ERR_OK(status)) {
521                 libnet_join_set_error_string(mem_ctx, r,
522                         "failed to determine domain functional level: %s",
523                         ads_errstr(status));
524                 return false;
525         }
526
527         /* go ahead and setup the default salt */
528
529         std_salt = kerberos_standard_des_salt();
530         if (!std_salt) {
531                 libnet_join_set_error_string(mem_ctx, r,
532                         "failed to obtain standard DES salt");
533                 return false;
534         }
535
536         salt = talloc_strdup(mem_ctx, std_salt);
537         if (!salt) {
538                 return false;
539         }
540
541         SAFE_FREE(std_salt);
542
543         /* if it's a Windows functional domain, we have to look for the UPN */
544
545         if (domain_func == DS_DOMAIN_FUNCTION_2000) {
546                 char *upn;
547
548                 upn = ads_get_upn(r->in.ads, mem_ctx,
549                                   r->in.machine_name);
550                 if (upn) {
551                         salt = talloc_strdup(mem_ctx, upn);
552                         if (!salt) {
553                                 return false;
554                         }
555                 }
556         }
557
558         return kerberos_secrets_store_des_salt(salt);
559 }
560
561 /****************************************************************
562 ****************************************************************/
563
564 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
565                                                   struct libnet_JoinCtx *r)
566 {
567         ADS_STATUS status;
568
569         if (!r->in.ads) {
570                 status = libnet_join_connect_ads(mem_ctx, r);
571                 if (!ADS_ERR_OK(status)) {
572                         return status;
573                 }
574         }
575
576         status = libnet_join_set_machine_spn(mem_ctx, r);
577         if (!ADS_ERR_OK(status)) {
578                 libnet_join_set_error_string(mem_ctx, r,
579                         "failed to set machine spn: %s",
580                         ads_errstr(status));
581                 return status;
582         }
583
584         status = libnet_join_set_os_attributes(mem_ctx, r);
585         if (!ADS_ERR_OK(status)) {
586                 libnet_join_set_error_string(mem_ctx, r,
587                         "failed to set machine os attributes: %s",
588                         ads_errstr(status));
589                 return status;
590         }
591
592         status = libnet_join_set_machine_upn(mem_ctx, r);
593         if (!ADS_ERR_OK(status)) {
594                 libnet_join_set_error_string(mem_ctx, r,
595                         "failed to set machine upn: %s",
596                         ads_errstr(status));
597                 return status;
598         }
599
600         if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
601                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
602         }
603
604         if (!libnet_join_create_keytab(mem_ctx, r)) {
605                 libnet_join_set_error_string(mem_ctx, r,
606                         "failed to create kerberos keytab");
607                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
608         }
609
610         return ADS_SUCCESS;
611 }
612 #endif /* WITH_ADS */
613
614 /****************************************************************
615  Store the machine password and domain SID
616 ****************************************************************/
617
618 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
619                                                  struct libnet_JoinCtx *r)
620 {
621         if (!secrets_store_domain_sid(r->out.netbios_domain_name,
622                                       r->out.domain_sid))
623         {
624                 DEBUG(1,("Failed to save domain sid\n"));
625                 return false;
626         }
627
628         if (!secrets_store_machine_password(r->in.machine_password,
629                                             r->out.netbios_domain_name,
630                                             r->in.secure_channel_type))
631         {
632                 DEBUG(1,("Failed to save machine password\n"));
633                 return false;
634         }
635
636         return true;
637 }
638
639 /****************************************************************
640  Do the domain join
641 ****************************************************************/
642
643 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
644                                            struct libnet_JoinCtx *r)
645 {
646         struct cli_state *cli = NULL;
647         struct rpc_pipe_client *pipe_hnd = NULL;
648         POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
649         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
650         char *acct_name;
651         struct lsa_String lsa_acct_name;
652         uint32_t user_rid;
653         uint32_t acct_flags = ACB_WSTRUST;
654         uchar pwbuf[532];
655         struct MD5Context md5ctx;
656         uchar md5buffer[16];
657         DATA_BLOB digested_session_key;
658         uchar md4_trust_password[16];
659         union lsa_PolicyInformation *info = NULL;
660         struct samr_Ids user_rids;
661         struct samr_Ids name_types;
662         union samr_UserInfo user_info;
663
664         if (!r->in.machine_password) {
665                 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
666                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
667         }
668
669         status = cli_full_connection(&cli, NULL,
670                                      r->in.dc_name,
671                                      NULL, 0,
672                                      "IPC$", "IPC",
673                                      r->in.admin_account,
674                                      NULL,
675                                      r->in.admin_password,
676                                      0,
677                                      Undefined, NULL);
678
679         if (!NT_STATUS_IS_OK(status)) {
680                 goto done;
681         }
682
683         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
684         if (!pipe_hnd) {
685                 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
686                         nt_errstr(status)));
687                 goto done;
688         }
689
690         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
691                                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
692         if (!NT_STATUS_IS_OK(status)) {
693                 goto done;
694         }
695
696         status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
697                                              &lsa_pol,
698                                              LSA_POLICY_INFO_DNS,
699                                              &info);
700         if (NT_STATUS_IS_OK(status)) {
701                 r->out.domain_is_ad = true;
702                 r->out.netbios_domain_name = info->dns.name.string;
703                 r->out.dns_domain_name = info->dns.dns_domain.string;
704                 r->out.domain_sid = info->dns.sid;
705         }
706
707         if (!NT_STATUS_IS_OK(status)) {
708                 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
709                                                     &lsa_pol,
710                                                     LSA_POLICY_INFO_ACCOUNT_DOMAIN,
711                                                     &info);
712                 if (!NT_STATUS_IS_OK(status)) {
713                         goto done;
714                 }
715
716                 r->out.netbios_domain_name = info->account_domain.name.string;
717                 r->out.domain_sid = info->account_domain.sid;
718         }
719
720         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
721         cli_rpc_pipe_close(pipe_hnd);
722
723         /* Open the domain */
724
725         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
726         if (!pipe_hnd) {
727                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
728                         nt_errstr(status)));
729                 goto done;
730         }
731
732         status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
733                                       pipe_hnd->cli->desthost,
734                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
735                                       &sam_pol);
736         if (!NT_STATUS_IS_OK(status)) {
737                 goto done;
738         }
739
740         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
741                                         &sam_pol,
742                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
743                                         r->out.domain_sid,
744                                         &domain_pol);
745         if (!NT_STATUS_IS_OK(status)) {
746                 goto done;
747         }
748
749         /* Create domain user */
750
751         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
752         strlower_m(acct_name);
753
754         init_lsa_String(&lsa_acct_name, acct_name);
755
756         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
757                 uint32_t access_desired =
758                         SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
759                         SEC_STD_WRITE_DAC | SEC_STD_DELETE |
760                         SAMR_USER_ACCESS_SET_PASSWORD |
761                         SAMR_USER_ACCESS_GET_ATTRIBUTES |
762                         SAMR_USER_ACCESS_SET_ATTRIBUTES;
763                 uint32_t access_granted = 0;
764
765                 /* Don't try to set any acct_flags flags other than ACB_WSTRUST */
766
767                 DEBUG(10,("Creating account with desired access mask: %d\n",
768                         access_desired));
769
770                 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
771                                                  &domain_pol,
772                                                  &lsa_acct_name,
773                                                  ACB_WSTRUST,
774                                                  access_desired,
775                                                  &user_pol,
776                                                  &access_granted,
777                                                  &user_rid);
778                 if (!NT_STATUS_IS_OK(status) &&
779                     !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
780
781                         DEBUG(10,("Creation of workstation account failed: %s\n",
782                                 nt_errstr(status)));
783
784                         /* If NT_STATUS_ACCESS_DENIED then we have a valid
785                            username/password combo but the user does not have
786                            administrator access. */
787
788                         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
789                                 libnet_join_set_error_string(mem_ctx, r,
790                                         "User specified does not have "
791                                         "administrator privileges");
792                         }
793
794                         return status;
795                 }
796
797                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
798                         if (!(r->in.join_flags &
799                               WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
800                                 goto done;
801                         }
802                 }
803
804                 /* We *must* do this.... don't ask... */
805
806                 if (NT_STATUS_IS_OK(status)) {
807                         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
808                 }
809         }
810
811         status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
812                                          &domain_pol,
813                                          1,
814                                          &lsa_acct_name,
815                                          &user_rids,
816                                          &name_types);
817         if (!NT_STATUS_IS_OK(status)) {
818                 goto done;
819         }
820
821         if (name_types.ids[0] != SID_NAME_USER) {
822                 DEBUG(0,("%s is not a user account (type=%d)\n",
823                         acct_name, name_types.ids[0]));
824                 status = NT_STATUS_INVALID_WORKSTATION;
825                 goto done;
826         }
827
828         user_rid = user_rids.ids[0];
829
830         /* Open handle on user */
831
832         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
833                                       &domain_pol,
834                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
835                                       user_rid,
836                                       &user_pol);
837         if (!NT_STATUS_IS_OK(status)) {
838                 goto done;
839         }
840
841         /* Create a random machine account password and generate the hash */
842
843         E_md4hash(r->in.machine_password, md4_trust_password);
844         encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
845
846         generate_random_buffer((uint8_t*)md5buffer, sizeof(md5buffer));
847         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
848
849         MD5Init(&md5ctx);
850         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
851         MD5Update(&md5ctx, cli->user_session_key.data,
852                   cli->user_session_key.length);
853         MD5Final(digested_session_key.data, &md5ctx);
854
855         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
856         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
857
858         /* Fill in the additional account flags now */
859
860         acct_flags |= ACB_PWNOEXP;
861         if (r->out.domain_is_ad) {
862 #if !defined(ENCTYPE_ARCFOUR_HMAC)
863                 acct_flags |= ACB_USE_DES_KEY_ONLY;
864 #endif
865                 ;;
866         }
867
868         /* Set password and account flags on machine account */
869
870         ZERO_STRUCT(user_info.info25);
871
872         user_info.info25.info.fields_present = ACCT_NT_PWD_SET |
873                                                ACCT_LM_PWD_SET |
874                                                SAMR_FIELD_ACCT_FLAGS;
875
876         user_info.info25.info.acct_flags = acct_flags;
877         memcpy(&user_info.info25.password.data, pwbuf, sizeof(pwbuf));
878
879         status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
880                                          &user_pol,
881                                          25,
882                                          &user_info);
883
884         if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
885
886                 uchar pwbuf2[516];
887
888                 encode_pw_buffer(pwbuf2, r->in.machine_password, STR_UNICODE);
889
890                 /* retry with level 24 */
891                 init_samr_user_info24(&user_info.info24, pwbuf2, 24);
892
893                 SamOEMhashBlob(user_info.info24.password.data, 516,
894                                &cli->user_session_key);
895
896                 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
897                                                   &user_pol,
898                                                   24,
899                                                   &user_info);
900         }
901
902         if (!NT_STATUS_IS_OK(status)) {
903                 libnet_join_set_error_string(mem_ctx, r,
904                         "Failed to set password for machine account (%s)\n",
905                         nt_errstr(status));
906                 goto done;
907         }
908
909         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
910         cli_rpc_pipe_close(pipe_hnd);
911
912         status = NT_STATUS_OK;
913  done:
914         if (cli) {
915                 cli_shutdown(cli);
916         }
917
918         return status;
919 }
920
921 /****************************************************************
922 ****************************************************************/
923
924 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
925                         const char *machine_name,
926                         const char *dc_name)
927 {
928         uint32_t neg_flags = NETLOGON_NEG_SELECT_AUTH2_FLAGS |
929                              NETLOGON_NEG_SCHANNEL;
930         struct cli_state *cli = NULL;
931         struct rpc_pipe_client *pipe_hnd = NULL;
932         struct rpc_pipe_client *netlogon_pipe = NULL;
933         NTSTATUS status;
934         char *machine_password = NULL;
935         char *machine_account = NULL;
936
937         if (!dc_name) {
938                 return NT_STATUS_INVALID_PARAMETER;
939         }
940
941         if (!secrets_init()) {
942                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
943         }
944
945         machine_password = secrets_fetch_machine_password(netbios_domain_name,
946                                                           NULL, NULL);
947         if (!machine_password) {
948                 return NT_STATUS_NO_TRUST_LSA_SECRET;
949         }
950
951         asprintf(&machine_account, "%s$", machine_name);
952         if (!machine_account) {
953                 SAFE_FREE(machine_password);
954                 return NT_STATUS_NO_MEMORY;
955         }
956
957         status = cli_full_connection(&cli, NULL,
958                                      dc_name,
959                                      NULL, 0,
960                                      "IPC$", "IPC",
961                                      machine_account,
962                                      NULL,
963                                      machine_password,
964                                      0,
965                                      Undefined, NULL);
966         free(machine_account);
967         free(machine_password);
968
969         if (!NT_STATUS_IS_OK(status)) {
970                 status = cli_full_connection(&cli, NULL,
971                                              dc_name,
972                                              NULL, 0,
973                                              "IPC$", "IPC",
974                                              "",
975                                              NULL,
976                                              "",
977                                              0,
978                                              Undefined, NULL);
979         }
980
981         if (!NT_STATUS_IS_OK(status)) {
982                 return status;
983         }
984
985         netlogon_pipe = get_schannel_session_key(cli,
986                                                  netbios_domain_name,
987                                                  &neg_flags, &status);
988         if (!netlogon_pipe) {
989                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
990                         cli_shutdown(cli);
991                         return NT_STATUS_OK;
992                 }
993
994                 DEBUG(0,("libnet_join_ok: failed to get schannel session "
995                         "key from server %s for domain %s. Error was %s\n",
996                 cli->desthost, netbios_domain_name, nt_errstr(status)));
997                 cli_shutdown(cli);
998                 return status;
999         }
1000
1001         if (!lp_client_schannel()) {
1002                 cli_shutdown(cli);
1003                 return NT_STATUS_OK;
1004         }
1005
1006         pipe_hnd = cli_rpc_pipe_open_schannel_with_key(cli, PI_NETLOGON,
1007                                                        PIPE_AUTH_LEVEL_PRIVACY,
1008                                                        netbios_domain_name,
1009                                                        netlogon_pipe->dc,
1010                                                        &status);
1011
1012         cli_shutdown(cli);
1013
1014         if (!pipe_hnd) {
1015                 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1016                         "on netlogon pipe to server %s for domain %s. "
1017                         "Error was %s\n",
1018                         cli->desthost, netbios_domain_name, nt_errstr(status)));
1019                 return status;
1020         }
1021
1022         return NT_STATUS_OK;
1023 }
1024
1025 /****************************************************************
1026 ****************************************************************/
1027
1028 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1029                                       struct libnet_JoinCtx *r)
1030 {
1031         NTSTATUS status;
1032
1033         status = libnet_join_ok(r->out.netbios_domain_name,
1034                                 r->in.machine_name,
1035                                 r->in.dc_name);
1036         if (!NT_STATUS_IS_OK(status)) {
1037                 libnet_join_set_error_string(mem_ctx, r,
1038                         "failed to verify domain membership after joining: %s",
1039                         get_friendly_nt_error_msg(status));
1040                 return WERR_SETUP_NOT_JOINED;
1041         }
1042
1043         return WERR_OK;
1044 }
1045
1046 /****************************************************************
1047 ****************************************************************/
1048
1049 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1050                                                     struct libnet_UnjoinCtx *r)
1051 {
1052         if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1053                 return false;
1054         }
1055
1056         if (!secrets_delete_domain_sid(lp_workgroup())) {
1057                 return false;
1058         }
1059
1060         return true;
1061 }
1062
1063 /****************************************************************
1064 ****************************************************************/
1065
1066 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1067                                              struct libnet_UnjoinCtx *r)
1068 {
1069         struct cli_state *cli = NULL;
1070         struct rpc_pipe_client *pipe_hnd = NULL;
1071         POLICY_HND sam_pol, domain_pol, user_pol;
1072         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1073         char *acct_name;
1074         uint32_t user_rid;
1075         struct lsa_String lsa_acct_name;
1076         struct samr_Ids user_rids;
1077         struct samr_Ids name_types;
1078         union samr_UserInfo *info = NULL;
1079
1080         status = cli_full_connection(&cli, NULL,
1081                                      r->in.dc_name,
1082                                      NULL, 0,
1083                                      "IPC$", "IPC",
1084                                      r->in.admin_account,
1085                                      NULL,
1086                                      r->in.admin_password,
1087                                      0, Undefined, NULL);
1088
1089         if (!NT_STATUS_IS_OK(status)) {
1090                 goto done;
1091         }
1092
1093         /* Open the domain */
1094
1095         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
1096         if (!pipe_hnd) {
1097                 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1098                         nt_errstr(status)));
1099                 goto done;
1100         }
1101
1102         status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1103                                       pipe_hnd->cli->desthost,
1104                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
1105                                       &sam_pol);
1106         if (!NT_STATUS_IS_OK(status)) {
1107                 goto done;
1108         }
1109
1110         status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1111                                         &sam_pol,
1112                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1113                                         r->in.domain_sid,
1114                                         &domain_pol);
1115         if (!NT_STATUS_IS_OK(status)) {
1116                 goto done;
1117         }
1118
1119         /* Create domain user */
1120
1121         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1122         strlower_m(acct_name);
1123
1124         init_lsa_String(&lsa_acct_name, acct_name);
1125
1126         status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1127                                          &domain_pol,
1128                                          1,
1129                                          &lsa_acct_name,
1130                                          &user_rids,
1131                                          &name_types);
1132
1133         if (!NT_STATUS_IS_OK(status)) {
1134                 goto done;
1135         }
1136
1137         if (name_types.ids[0] != SID_NAME_USER) {
1138                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1139                         name_types.ids[0]));
1140                 status = NT_STATUS_INVALID_WORKSTATION;
1141                 goto done;
1142         }
1143
1144         user_rid = user_rids.ids[0];
1145
1146         /* Open handle on user */
1147
1148         status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1149                                       &domain_pol,
1150                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
1151                                       user_rid,
1152                                       &user_pol);
1153         if (!NT_STATUS_IS_OK(status)) {
1154                 goto done;
1155         }
1156
1157         /* Get user info */
1158
1159         status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1160                                            &user_pol,
1161                                            16,
1162                                            &info);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1165                 goto done;
1166         }
1167
1168         /* now disable and setuser info */
1169
1170         info->info16.acct_flags |= ACB_DISABLED;
1171
1172         status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1173                                          &user_pol,
1174                                          16,
1175                                          info);
1176
1177         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1178
1179 done:
1180         if (pipe_hnd) {
1181                 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1182                 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1183                 cli_rpc_pipe_close(pipe_hnd);
1184         }
1185
1186         if (cli) {
1187                 cli_shutdown(cli);
1188         }
1189
1190         return status;
1191 }
1192
1193 /****************************************************************
1194 ****************************************************************/
1195
1196 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1197 {
1198         WERROR werr;
1199         struct smbconf_ctx *ctx;
1200
1201         werr = smbconf_init_reg(r, &ctx, NULL);
1202         if (!W_ERROR_IS_OK(werr)) {
1203                 goto done;
1204         }
1205
1206         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1207
1208                 werr = smbconf_set_global_parameter(ctx, "security", "user");
1209                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1210
1211                 werr = smbconf_set_global_parameter(ctx, "workgroup",
1212                                                     r->in.domain_name);
1213                 goto done;
1214         }
1215
1216         werr = smbconf_set_global_parameter(ctx, "security", "domain");
1217         W_ERROR_NOT_OK_GOTO_DONE(werr);
1218
1219         werr = smbconf_set_global_parameter(ctx, "workgroup",
1220                                             r->out.netbios_domain_name);
1221         W_ERROR_NOT_OK_GOTO_DONE(werr);
1222
1223         if (r->out.domain_is_ad) {
1224                 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1225                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1226
1227                 werr = smbconf_set_global_parameter(ctx, "realm",
1228                                                     r->out.dns_domain_name);
1229                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1230         }
1231
1232  done:
1233         smbconf_shutdown(ctx);
1234         return werr;
1235 }
1236
1237 /****************************************************************
1238 ****************************************************************/
1239
1240 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1241 {
1242         WERROR werr = WERR_OK;
1243         struct smbconf_ctx *ctx;
1244
1245         werr = smbconf_init_reg(r, &ctx, NULL);
1246         if (!W_ERROR_IS_OK(werr)) {
1247                 goto done;
1248         }
1249
1250         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1251
1252                 werr = smbconf_set_global_parameter(ctx, "security", "user");
1253                 W_ERROR_NOT_OK_GOTO_DONE(werr);
1254                 smbconf_delete_global_parameter(ctx, "realm");
1255         }
1256
1257  done:
1258         smbconf_shutdown(ctx);
1259         return werr;
1260 }
1261
1262 /****************************************************************
1263 ****************************************************************/
1264
1265 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1266 {
1267         WERROR werr;
1268
1269         if (!W_ERROR_IS_OK(r->out.result)) {
1270                 return r->out.result;
1271         }
1272
1273         if (!r->in.modify_config) {
1274                 return WERR_OK;
1275         }
1276
1277         werr = do_join_modify_vals_config(r);
1278         if (!W_ERROR_IS_OK(werr)) {
1279                 return werr;
1280         }
1281
1282         r->out.modified_config = true;
1283         r->out.result = werr;
1284
1285         return werr;
1286 }
1287
1288 /****************************************************************
1289 ****************************************************************/
1290
1291 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1292 {
1293         WERROR werr;
1294
1295         if (!W_ERROR_IS_OK(r->out.result)) {
1296                 return r->out.result;
1297         }
1298
1299         if (!r->in.modify_config) {
1300                 return WERR_OK;
1301         }
1302
1303         werr = do_unjoin_modify_vals_config(r);
1304         if (!W_ERROR_IS_OK(werr)) {
1305                 return werr;
1306         }
1307
1308         r->out.modified_config = true;
1309         r->out.result = werr;
1310
1311         return werr;
1312 }
1313
1314 /****************************************************************
1315 ****************************************************************/
1316
1317 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1318                                          struct libnet_JoinCtx *r)
1319 {
1320         if (!r->in.domain_name) {
1321                 libnet_join_set_error_string(mem_ctx, r,
1322                         "No domain name defined");
1323                 return WERR_INVALID_PARAM;
1324         }
1325
1326         if (r->in.modify_config && !lp_config_backend_is_registry()) {
1327                 libnet_join_set_error_string(mem_ctx, r,
1328                         "Configuration manipulation requested but not "
1329                         "supported by backend");
1330                 return WERR_NOT_SUPPORTED;
1331         }
1332
1333         if (IS_DC) {
1334                 return WERR_SETUP_DOMAIN_CONTROLLER;
1335         }
1336
1337         if (!secrets_init()) {
1338                 libnet_join_set_error_string(mem_ctx, r,
1339                         "Unable to open secrets database");
1340                 return WERR_CAN_NOT_COMPLETE;
1341         }
1342
1343         return WERR_OK;
1344 }
1345
1346 /****************************************************************
1347 ****************************************************************/
1348
1349 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1350                                           struct libnet_JoinCtx *r)
1351 {
1352         WERROR werr;
1353
1354         if (!W_ERROR_IS_OK(r->out.result)) {
1355                 return r->out.result;
1356         }
1357
1358         werr = do_JoinConfig(r);
1359         if (!W_ERROR_IS_OK(werr)) {
1360                 return werr;
1361         }
1362
1363         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1364                 saf_store(r->in.domain_name, r->in.dc_name);
1365         }
1366
1367         return WERR_OK;
1368 }
1369
1370 /****************************************************************
1371 ****************************************************************/
1372
1373 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1374 {
1375         if (r->in.ads) {
1376                 ads_destroy(&r->in.ads);
1377         }
1378
1379         return 0;
1380 }
1381
1382 /****************************************************************
1383 ****************************************************************/
1384
1385 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1386 {
1387         if (r->in.ads) {
1388                 ads_destroy(&r->in.ads);
1389         }
1390
1391         return 0;
1392 }
1393
1394 /****************************************************************
1395 ****************************************************************/
1396
1397 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1398                            struct libnet_JoinCtx **r)
1399 {
1400         struct libnet_JoinCtx *ctx;
1401
1402         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1403         if (!ctx) {
1404                 return WERR_NOMEM;
1405         }
1406
1407         talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1408
1409         ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1410         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1411
1412         ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1413
1414         *r = ctx;
1415
1416         return WERR_OK;
1417 }
1418
1419 /****************************************************************
1420 ****************************************************************/
1421
1422 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1423                              struct libnet_UnjoinCtx **r)
1424 {
1425         struct libnet_UnjoinCtx *ctx;
1426
1427         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1428         if (!ctx) {
1429                 return WERR_NOMEM;
1430         }
1431
1432         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1433
1434         ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1435         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1436
1437         *r = ctx;
1438
1439         return WERR_OK;
1440 }
1441
1442 /****************************************************************
1443 ****************************************************************/
1444
1445 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1446                                 struct libnet_JoinCtx *r)
1447 {
1448         NTSTATUS status;
1449 #ifdef WITH_ADS
1450         ADS_STATUS ads_status;
1451 #endif /* WITH_ADS */
1452
1453         if (!r->in.dc_name) {
1454                 struct netr_DsRGetDCNameInfo *info;
1455                 status = dsgetdcname(mem_ctx,
1456                                      r->in.domain_name,
1457                                      NULL,
1458                                      NULL,
1459                                      DS_DIRECTORY_SERVICE_REQUIRED |
1460                                      DS_WRITABLE_REQUIRED |
1461                                      DS_RETURN_DNS_NAME,
1462                                      &info);
1463                 if (!NT_STATUS_IS_OK(status)) {
1464                         libnet_join_set_error_string(mem_ctx, r,
1465                                 "failed to find DC for domain %s",
1466                                 r->in.domain_name,
1467                                 get_friendly_nt_error_msg(status));
1468                         return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1469                 }
1470
1471                 r->in.dc_name = talloc_strdup(mem_ctx,
1472                                               info->dc_unc);
1473                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1474         }
1475
1476 #ifdef WITH_ADS
1477         if (r->in.account_ou) {
1478
1479                 ads_status = libnet_join_connect_ads(mem_ctx, r);
1480                 if (!ADS_ERR_OK(ads_status)) {
1481                         return WERR_DEFAULT_JOIN_REQUIRED;
1482                 }
1483
1484                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1485                 if (!ADS_ERR_OK(ads_status)) {
1486                         libnet_join_set_error_string(mem_ctx, r,
1487                                 "failed to precreate account in ou %s: %s",
1488                                 r->in.account_ou,
1489                                 ads_errstr(ads_status));
1490                         return WERR_DEFAULT_JOIN_REQUIRED;
1491                 }
1492
1493                 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1494         }
1495 #endif /* WITH_ADS */
1496
1497         status = libnet_join_joindomain_rpc(mem_ctx, r);
1498         if (!NT_STATUS_IS_OK(status)) {
1499                 libnet_join_set_error_string(mem_ctx, r,
1500                         "failed to join domain over rpc: %s",
1501                         get_friendly_nt_error_msg(status));
1502                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1503                         return WERR_SETUP_ALREADY_JOINED;
1504                 }
1505                 return ntstatus_to_werror(status);
1506         }
1507
1508         if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1509                 return WERR_SETUP_NOT_JOINED;
1510         }
1511
1512 #ifdef WITH_ADS
1513         if (r->out.domain_is_ad) {
1514                 ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
1515                 if (!ADS_ERR_OK(ads_status)) {
1516                         return WERR_GENERAL_FAILURE;
1517                 }
1518         }
1519 #endif /* WITH_ADS */
1520
1521         return WERR_OK;
1522 }
1523
1524 /****************************************************************
1525 ****************************************************************/
1526
1527 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1528                    struct libnet_JoinCtx *r)
1529 {
1530         WERROR werr;
1531
1532         if (r->in.debug) {
1533                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1534         }
1535
1536         werr = libnet_join_pre_processing(mem_ctx, r);
1537         if (!W_ERROR_IS_OK(werr)) {
1538                 goto done;
1539         }
1540
1541         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1542                 werr = libnet_DomainJoin(mem_ctx, r);
1543                 if (!W_ERROR_IS_OK(werr)) {
1544                         goto done;
1545                 }
1546
1547                 werr = libnet_join_post_verify(mem_ctx, r);
1548                 if (!W_ERROR_IS_OK(werr)) {
1549                         goto done;
1550                 }
1551         }
1552
1553         werr = libnet_join_post_processing(mem_ctx, r);
1554         if (!W_ERROR_IS_OK(werr)) {
1555                 goto done;
1556         }
1557  done:
1558         r->out.result = werr;
1559
1560         if (r->in.debug) {
1561                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1562         }
1563         return werr;
1564 }
1565
1566 /****************************************************************
1567 ****************************************************************/
1568
1569 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1570                                   struct libnet_UnjoinCtx *r)
1571 {
1572         NTSTATUS status;
1573
1574         if (!r->in.domain_sid) {
1575                 struct dom_sid sid;
1576                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
1577                         libnet_unjoin_set_error_string(mem_ctx, r,
1578                                 "Unable to fetch domain sid: are we joined?");
1579                         return WERR_SETUP_NOT_JOINED;
1580                 }
1581                 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
1582                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
1583         }
1584
1585         if (!r->in.dc_name) {
1586                 struct netr_DsRGetDCNameInfo *info;
1587                 status = dsgetdcname(mem_ctx,
1588                                      r->in.domain_name,
1589                                      NULL,
1590                                      NULL,
1591                                      DS_DIRECTORY_SERVICE_REQUIRED |
1592                                      DS_WRITABLE_REQUIRED |
1593                                      DS_RETURN_DNS_NAME,
1594                                      &info);
1595                 if (!NT_STATUS_IS_OK(status)) {
1596                         libnet_unjoin_set_error_string(mem_ctx, r,
1597                                 "failed to find DC for domain %s",
1598                                 r->in.domain_name,
1599                                 get_friendly_nt_error_msg(status));
1600                         return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1601                 }
1602
1603                 r->in.dc_name = talloc_strdup(mem_ctx,
1604                                               info->dc_unc);
1605                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1606         }
1607
1608         status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1609         if (!NT_STATUS_IS_OK(status)) {
1610                 libnet_unjoin_set_error_string(mem_ctx, r,
1611                         "failed to disable machine account via rpc: %s",
1612                         get_friendly_nt_error_msg(status));
1613                 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1614                         return WERR_SETUP_NOT_JOINED;
1615                 }
1616                 return ntstatus_to_werror(status);
1617         }
1618
1619         r->out.disabled_machine_account = true;
1620
1621 #ifdef WITH_ADS
1622         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1623                 ADS_STATUS ads_status;
1624                 libnet_unjoin_connect_ads(mem_ctx, r);
1625                 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1626                 if (!ADS_ERR_OK(ads_status)) {
1627                         libnet_unjoin_set_error_string(mem_ctx, r,
1628                                 "failed to remove machine account from AD: %s",
1629                                 ads_errstr(ads_status));
1630                 } else {
1631                         r->out.deleted_machine_account = true;
1632                         /* dirty hack */
1633                         r->out.dns_domain_name = talloc_strdup(mem_ctx,
1634                                                                r->in.ads->server.realm);
1635                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
1636                 }
1637         }
1638 #endif /* WITH_ADS */
1639
1640         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1641
1642         return WERR_OK;
1643 }
1644
1645 /****************************************************************
1646 ****************************************************************/
1647
1648 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
1649                                            struct libnet_UnjoinCtx *r)
1650 {
1651         if (!r->in.domain_name) {
1652                 libnet_unjoin_set_error_string(mem_ctx, r,
1653                         "No domain name defined");
1654                 return WERR_INVALID_PARAM;
1655         }
1656
1657         if (r->in.modify_config && !lp_config_backend_is_registry()) {
1658                 libnet_unjoin_set_error_string(mem_ctx, r,
1659                         "Configuration manipulation requested but not "
1660                         "supported by backend");
1661                 return WERR_NOT_SUPPORTED;
1662         }
1663
1664         if (IS_DC) {
1665                 return WERR_SETUP_DOMAIN_CONTROLLER;
1666         }
1667
1668         if (!secrets_init()) {
1669                 libnet_unjoin_set_error_string(mem_ctx, r,
1670                         "Unable to open secrets database");
1671                 return WERR_CAN_NOT_COMPLETE;
1672         }
1673
1674         return WERR_OK;
1675 }
1676
1677 /****************************************************************
1678 ****************************************************************/
1679
1680 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
1681                                             struct libnet_UnjoinCtx *r)
1682 {
1683         saf_delete(r->out.netbios_domain_name);
1684         saf_delete(r->out.dns_domain_name);
1685
1686         return libnet_unjoin_config(r);
1687 }
1688
1689 /****************************************************************
1690 ****************************************************************/
1691
1692 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1693                      struct libnet_UnjoinCtx *r)
1694 {
1695         WERROR werr;
1696
1697         if (r->in.debug) {
1698                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
1699         }
1700
1701         werr = libnet_unjoin_pre_processing(mem_ctx, r);
1702         if (!W_ERROR_IS_OK(werr)) {
1703                 goto done;
1704         }
1705
1706         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1707                 werr = libnet_DomainUnjoin(mem_ctx, r);
1708                 if (!W_ERROR_IS_OK(werr)) {
1709                         libnet_unjoin_config(r);
1710                         goto done;
1711                 }
1712         }
1713
1714         werr = libnet_unjoin_post_processing(mem_ctx, r);
1715         if (!W_ERROR_IS_OK(werr)) {
1716                 goto done;
1717         }
1718
1719  done:
1720         r->out.result = werr;
1721
1722         if (r->in.debug) {
1723                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
1724         }
1725
1726         return werr;
1727 }