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

Generated by: LCOV version 1.14