LCOV - code coverage report
Current view: top level - source3/libnet - libnet_join.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 829 1420 58.4 %
Date: 2024-05-31 13:13:24 Functions: 47 50 94.0 %

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

Generated by: LCOV version 1.14