LCOV - code coverage report
Current view: top level - source3/libnet - libnet_join.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 647 1405 46.0 %
Date: 2024-06-13 04:01:37 Functions: 34 50 68.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           2 : static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
      89             :                                          struct libnet_JoinCtx *r,
      90             :                                          const char *format, ...)
      91             : {
      92             :         va_list args;
      93             : 
      94           2 :         if (r->out.error_string) {
      95           0 :                 return;
      96             :         }
      97             : 
      98           2 :         va_start(args, format);
      99           2 :         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
     100           2 :         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           0 : static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
     112             :                                            struct libnet_UnjoinCtx *r,
     113             :                                            const char *format, ...)
     114             : {
     115             :         va_list args;
     116             : 
     117           0 :         if (r->out.error_string) {
     118           0 :                 return;
     119             :         }
     120             : 
     121           0 :         va_start(args, format);
     122           0 :         r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
     123           0 :         va_end(args);
     124             : }
     125             : 
     126             : #ifdef HAVE_ADS
     127             : 
     128             : /****************************************************************
     129             : ****************************************************************/
     130             : 
     131          48 : 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          48 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
     141             :         ADS_STATUS status;
     142          48 :         ADS_STRUCT *my_ads = NULL;
     143             :         char *cp;
     144             :         enum credentials_use_kerberos krb5_state;
     145             : 
     146          48 :         my_ads = ads_init(tmp_ctx,
     147             :                           dns_domain_name,
     148             :                           netbios_domain_name,
     149             :                           dc_name,
     150             :                           ADS_SASL_SEAL);
     151          48 :         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          48 :         krb5_state = lp_client_use_kerberos();
     158          48 :         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          48 :         case CRED_USE_KERBEROS_DESIRED:
     164          48 :                 my_ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
     165          48 :                 my_ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
     166          48 :                 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          48 :         if (user_name) {
     174          48 :                 TALLOC_FREE(my_ads->auth.user_name);
     175          48 :                 my_ads->auth.user_name = talloc_strdup(my_ads, user_name);
     176          48 :                 if (my_ads->auth.user_name == NULL) {
     177           0 :                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     178           0 :                         goto out;
     179             :                 }
     180          48 :                 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
     181          26 :                         *cp++ = '\0';
     182          26 :                         TALLOC_FREE(my_ads->auth.realm);
     183          26 :                         my_ads->auth.realm = talloc_asprintf_strupper_m(my_ads, "%s", cp);
     184          26 :                         if (my_ads->auth.realm == NULL) {
     185           0 :                                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     186           0 :                                 goto out;
     187             :                         }
     188             :                 }
     189             :         }
     190             : 
     191          48 :         if (password) {
     192          48 :                 TALLOC_FREE(my_ads->auth.password);
     193          48 :                 my_ads->auth.password = talloc_strdup(my_ads, password);
     194          48 :                 if (my_ads->auth.password == NULL) {
     195           0 :                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     196           0 :                         goto out;
     197             :                 }
     198             :         }
     199             : 
     200          48 :         if (ccname != NULL) {
     201          32 :                 TALLOC_FREE(my_ads->auth.ccache_name);
     202          32 :                 my_ads->auth.ccache_name = talloc_strdup(my_ads, ccname);
     203          32 :                 if (my_ads->auth.ccache_name == NULL) {
     204           0 :                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     205           0 :                         goto out;
     206             :                 }
     207          32 :                 setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
     208             :         }
     209             : 
     210          48 :         status = ads_connect_user_creds(my_ads);
     211          48 :         if (!ADS_ERR_OK(status)) {
     212           0 :                 goto out;
     213             :         }
     214             : 
     215          48 :         *ads = talloc_move(mem_ctx, &my_ads);
     216             : 
     217          48 :         status = ADS_SUCCESS;
     218          48 : out:
     219          48 :         TALLOC_FREE(tmp_ctx);
     220          48 :         return status;
     221             : }
     222             : 
     223             : /****************************************************************
     224             : ****************************************************************/
     225             : 
     226          48 : static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
     227             :                                           struct libnet_JoinCtx *r,
     228             :                                           bool use_machine_creds)
     229             : {
     230             :         ADS_STATUS status;
     231             :         const char *username;
     232             :         const char *password;
     233          48 :         const char *ccname = NULL;
     234             : 
     235          48 :         if (use_machine_creds) {
     236          35 :                 if (r->in.machine_name == NULL ||
     237          22 :                     r->in.machine_password == NULL) {
     238           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
     239             :                 }
     240          22 :                 username = talloc_asprintf(mem_ctx, "%s$",
     241             :                                            r->in.machine_name);
     242          22 :                 if (username == NULL) {
     243           0 :                         return ADS_ERROR(LDAP_NO_MEMORY);
     244             :                 }
     245          22 :                 password = r->in.machine_password;
     246          22 :                 ccname = "MEMORY:libnet_join_machine_creds";
     247             :         } else {
     248          26 :                 char *p = NULL;
     249             : 
     250          26 :                 username = r->in.admin_account;
     251             : 
     252          26 :                 p = strchr(r->in.admin_account, '@');
     253          26 :                 if (p == NULL) {
     254          26 :                         username = talloc_asprintf(mem_ctx, "%s@%s",
     255             :                                                    r->in.admin_account,
     256             :                                                    r->in.admin_domain);
     257             :                 }
     258          26 :                 if (username == NULL) {
     259           0 :                         return ADS_ERROR(LDAP_NO_MEMORY);
     260             :                 }
     261          26 :                 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          26 :                 if (!r->in.use_kerberos) {
     269          10 :                         ccname = "MEMORY:libnet_join_user_creds";
     270             :                 }
     271             :         }
     272             : 
     273          48 :         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          48 :                                     &r->in.ads);
     281          48 :         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          48 :         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          48 :         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          48 :         r->out.domain_is_ad = true;
     301             : 
     302          48 :         return ADS_SUCCESS;
     303             : }
     304             : 
     305             : /****************************************************************
     306             : ****************************************************************/
     307             : 
     308          26 : static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
     309             :                                                struct libnet_JoinCtx *r)
     310             : {
     311          26 :         return libnet_join_connect_ads(mem_ctx, r, false);
     312             : }
     313             : 
     314             : /****************************************************************
     315             : ****************************************************************/
     316             : 
     317          22 : static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
     318             :                                                   struct libnet_JoinCtx *r)
     319             : {
     320          22 :         return libnet_join_connect_ads(mem_ctx, r, true);
     321             : }
     322             : 
     323             : /****************************************************************
     324             : ****************************************************************/
     325             : 
     326           0 : static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
     327             :                                             struct libnet_UnjoinCtx *r)
     328             : {
     329             :         ADS_STATUS status;
     330             : 
     331           0 :         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           0 :                                     &r->in.ads);
     339           0 :         if (!ADS_ERR_OK(status)) {
     340           0 :                 libnet_unjoin_set_error_string(mem_ctx, r,
     341             :                         "failed to connect to AD: %s",
     342             :                         ads_errstr(status));
     343             :         }
     344             : 
     345           0 :         return status;
     346             : }
     347             : 
     348             : /****************************************************************
     349             :  join a domain using ADS (LDAP mods)
     350             : ****************************************************************/
     351             : 
     352          26 : static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
     353             :                                                      struct libnet_JoinCtx *r)
     354             : {
     355             :         ADS_STATUS status;
     356          26 :         LDAPMessage *res = NULL;
     357          26 :         const char *attrs[] = { "dn", NULL };
     358          26 :         bool moved = false;
     359             : 
     360          26 :         status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
     361          26 :         if (!ADS_ERR_OK(status)) {
     362           0 :                 return status;
     363             :         }
     364             : 
     365          26 :         status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
     366          26 :         if (!ADS_ERR_OK(status)) {
     367           0 :                 return status;
     368             :         }
     369             : 
     370          26 :         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          26 :         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          26 :         if (r->in.machine_password == NULL) {
     381          26 :                 r->in.machine_password =
     382          26 :                         trust_pw_new_value(mem_ctx,
     383             :                                            r->in.secure_channel_type,
     384             :                                            SEC_ADS);
     385          26 :                 if (r->in.machine_password == NULL) {
     386           0 :                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     387             :                 }
     388             :         }
     389             : 
     390          26 :         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          26 :         if (ADS_ERR_OK(status)) {
     398          26 :                 DBG_WARNING("Machine account successfully created\n");
     399          26 :                 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           0 : static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
     430             :                                                     struct libnet_UnjoinCtx *r)
     431             : {
     432             :         ADS_STATUS status;
     433             : 
     434           0 :         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           0 :         status = ads_leave_realm(r->in.ads, r->in.machine_name);
     445           0 :         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           0 :         return ADS_SUCCESS;
     453             : }
     454             : 
     455             : /****************************************************************
     456             : ****************************************************************/
     457             : 
     458          74 : static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
     459             :                                                 struct libnet_JoinCtx *r)
     460             : {
     461             :         ADS_STATUS status;
     462          74 :         LDAPMessage *res = NULL;
     463          74 :         char *dn = NULL;
     464             :         struct dom_sid sid;
     465             : 
     466          74 :         if (!r->in.machine_name) {
     467           0 :                 return ADS_ERROR(LDAP_NO_MEMORY);
     468             :         }
     469             : 
     470          74 :         status = ads_find_machine_acct(r->in.ads,
     471             :                                        &res,
     472             :                                        r->in.machine_name);
     473          74 :         if (!ADS_ERR_OK(status)) {
     474           0 :                 return status;
     475             :         }
     476             : 
     477          74 :         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          74 :         dn = ads_get_dn(r->in.ads, mem_ctx, res);
     483          74 :         if (!dn) {
     484           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     485           0 :                 goto done;
     486             :         }
     487             : 
     488          74 :         r->out.dn = talloc_strdup(mem_ctx, dn);
     489          74 :         if (!r->out.dn) {
     490           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     491           0 :                 goto done;
     492             :         }
     493             : 
     494          74 :         if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
     495             :                              &r->out.set_encryption_types)) {
     496          70 :                 r->out.set_encryption_types = 0;
     497             :         }
     498             : 
     499          74 :         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          74 :         dom_sid_split_rid(mem_ctx, &sid, NULL, &r->out.account_rid);
     505          74 :  done:
     506          74 :         ads_msgfree(r->in.ads, res);
     507          74 :         TALLOC_FREE(dn);
     508             : 
     509          74 :         return status;
     510             : }
     511             : 
     512          26 : 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             :         ADS_STATUS status;
     518             : 
     519          26 :         if (r->in.machine_name == NULL) {
     520           0 :                 return ADS_ERROR_SYSTEM(EINVAL);
     521             :         }
     522             : 
     523          41 :         status = ads_get_service_principal_names(mem_ctx,
     524          26 :                                                  r->in.ads,
     525             :                                                  r->in.machine_name,
     526             :                                                  spn_array,
     527             :                                                  num_spns);
     528             : 
     529          26 :         return status;
     530             : }
     531             : 
     532          60 : static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const  char *spn,
     533             :                                const char ***array, size_t *num)
     534             : {
     535          60 :         bool ok = ads_element_in_array(*array, *num, spn);
     536          60 :         if (!ok) {
     537           8 :                 ok = add_string_to_array(mem_ctx, spn, array, num);
     538           8 :                 if (!ok) {
     539           0 :                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     540             :                 }
     541             :         }
     542          60 :         return ADS_SUCCESS;
     543             : }
     544             : 
     545             : /****************************************************************
     546             :  Set a machines dNSHostName and servicePrincipalName attributes
     547             : ****************************************************************/
     548             : 
     549          26 : static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
     550             :                                               struct libnet_JoinCtx *r)
     551             : {
     552          26 :         TALLOC_CTX *frame = talloc_stackframe();
     553             :         ADS_STATUS status;
     554             :         ADS_MODLIST mods;
     555             :         fstring my_fqdn;
     556             :         fstring my_alias;
     557          26 :         const char **spn_array = NULL;
     558          26 :         size_t num_spns = 0;
     559          26 :         char *spn = NULL;
     560          26 :         const char **netbios_aliases = NULL;
     561          26 :         const char **addl_hostnames = NULL;
     562             : 
     563             :         /* Find our DN */
     564             : 
     565          26 :         status = libnet_join_find_machine_acct(mem_ctx, r);
     566          26 :         if (!ADS_ERR_OK(status)) {
     567           0 :                 goto done;
     568             :         }
     569             : 
     570          26 :         status = libnet_join_get_machine_spns(frame,
     571             :                                               r,
     572             :                                               discard_const_p(char **, &spn_array),
     573             :                                               &num_spns);
     574          26 :         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          26 :         spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name);
     581          26 :         if (spn == NULL) {
     582           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     583           0 :                 goto done;
     584             :         }
     585          26 :         if (!strupper_m(spn)) {
     586           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     587           0 :                 goto done;
     588             :         }
     589             : 
     590          26 :         status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
     591          26 :         if (!ADS_ERR_OK(status)) {
     592           0 :                 goto done;
     593             :         }
     594             : 
     595          26 :         if (r->in.dnshostname != NULL) {
     596           6 :                 fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
     597             :         } else {
     598          20 :                 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
     599             :                              lp_dnsdomain());
     600             :         }
     601             : 
     602          26 :         if (!strlower_m(my_fqdn)) {
     603           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     604           0 :                 goto done;
     605             :         }
     606             : 
     607          26 :         spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
     608          26 :         if (spn == NULL) {
     609           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     610           0 :                 goto done;
     611             :         }
     612             : 
     613          26 :         status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
     614          26 :         if (!ADS_ERR_OK(status)) {
     615           0 :                 goto done;
     616             :         }
     617             : 
     618          43 :         for (netbios_aliases = lp_netbios_aliases();
     619          16 :              netbios_aliases != NULL && *netbios_aliases != NULL;
     620           4 :              netbios_aliases++) {
     621             :                 /*
     622             :                  * Add HOST/NETBIOSNAME
     623             :                  */
     624           4 :                 spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases);
     625           4 :                 if (spn == NULL) {
     626           0 :                         status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     627           0 :                         goto done;
     628             :                 }
     629           4 :                 if (!strupper_m(spn)) {
     630           0 :                         status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     631           0 :                         goto done;
     632             :                 }
     633             : 
     634           4 :                 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
     635           4 :                 if (!ADS_ERR_OK(status)) {
     636           0 :                         goto done;
     637             :                 }
     638             : 
     639             :                 /*
     640             :                  * Add HOST/netbiosname.domainname
     641             :                  */
     642           4 :                 fstr_sprintf(my_alias, "%s.%s",
     643             :                              *netbios_aliases,
     644             :                              lp_dnsdomain());
     645             : 
     646           4 :                 spn = talloc_asprintf(frame, "HOST/%s", my_alias);
     647           4 :                 if (spn == NULL) {
     648           0 :                         status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     649           0 :                         goto done;
     650             :                 }
     651             : 
     652           4 :                 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
     653           4 :                 if (!ADS_ERR_OK(status)) {
     654           0 :                         goto done;
     655             :                 }
     656             :         }
     657             : 
     658          41 :         for (addl_hostnames = lp_additional_dns_hostnames();
     659          11 :              addl_hostnames != NULL && *addl_hostnames != NULL;
     660           0 :              addl_hostnames++) {
     661             : 
     662           0 :                 spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames);
     663           0 :                 if (spn == NULL) {
     664           0 :                         status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     665           0 :                         goto done;
     666             :                 }
     667             : 
     668           0 :                 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
     669           0 :                 if (!ADS_ERR_OK(status)) {
     670           0 :                         goto done;
     671             :                 }
     672             :         }
     673             : 
     674             :         /* make sure to NULL terminate the array */
     675          26 :         spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1);
     676          26 :         if (spn_array == NULL) {
     677           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     678           0 :                 goto done;
     679             :         }
     680          26 :         spn_array[num_spns] = NULL;
     681             : 
     682          26 :         mods = ads_init_mods(mem_ctx);
     683          26 :         if (!mods) {
     684           0 :                 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     685           0 :                 goto done;
     686             :         }
     687             : 
     688             :         /* fields of primary importance */
     689             : 
     690          26 :         status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
     691          26 :         if (!ADS_ERR_OK(status)) {
     692           0 :                 goto done;
     693             :         }
     694             : 
     695          26 :         status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
     696             :                                  spn_array);
     697          26 :         if (!ADS_ERR_OK(status)) {
     698           0 :                 goto done;
     699             :         }
     700             : 
     701          26 :         addl_hostnames = lp_additional_dns_hostnames();
     702          26 :         if (addl_hostnames != NULL && *addl_hostnames != NULL) {
     703           0 :                 status = ads_mod_strlist(mem_ctx, &mods,
     704             :                                          "msDS-AdditionalDnsHostName",
     705             :                                          addl_hostnames);
     706           0 :                 if (!ADS_ERR_OK(status)) {
     707           0 :                         goto done;
     708             :                 }
     709             :         }
     710             : 
     711          26 :         status = ads_gen_mod(r->in.ads, r->out.dn, mods);
     712             : 
     713          26 : done:
     714          26 :         TALLOC_FREE(frame);
     715          26 :         return status;
     716             : }
     717             : 
     718             : /****************************************************************
     719             : ****************************************************************/
     720             : 
     721          26 : static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
     722             :                                               struct libnet_JoinCtx *r)
     723             : {
     724             :         ADS_STATUS status;
     725             :         ADS_MODLIST mods;
     726             : 
     727          26 :         if (!r->in.create_upn) {
     728          26 :                 return ADS_SUCCESS;
     729             :         }
     730             : 
     731             :         /* Find our DN */
     732             : 
     733           0 :         status = libnet_join_find_machine_acct(mem_ctx, r);
     734           0 :         if (!ADS_ERR_OK(status)) {
     735           0 :                 return status;
     736             :         }
     737             : 
     738           0 :         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           0 :         mods = ads_init_mods(mem_ctx);
     766           0 :         if (!mods) {
     767           0 :                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     768             :         }
     769             : 
     770             :         /* fields of primary importance */
     771             : 
     772           0 :         status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
     773           0 :         if (!ADS_ERR_OK(status)) {
     774           0 :                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
     775             :         }
     776             : 
     777           0 :         return ads_gen_mod(r->in.ads, r->out.dn, mods);
     778             : }
     779             : 
     780             : 
     781             : /****************************************************************
     782             : ****************************************************************/
     783             : 
     784          26 : static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
     785             :                                                 struct libnet_JoinCtx *r)
     786             : {
     787             :         ADS_STATUS status;
     788             :         ADS_MODLIST mods;
     789          26 :         char *os_sp = NULL;
     790             : 
     791          26 :         if (!r->in.os_name || !r->in.os_version ) {
     792          26 :                 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          22 : static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
     852             :                                          struct libnet_JoinCtx *r)
     853             : {
     854             :         ADS_STATUS status;
     855             :         ADS_MODLIST mods;
     856             :         const char *etype_list_str;
     857             : 
     858          22 :         etype_list_str = talloc_asprintf(mem_ctx, "%d",
     859             :                                          r->in.desired_encryption_types);
     860          22 :         if (!etype_list_str) {
     861           0 :                 return ADS_ERROR(LDAP_NO_MEMORY);
     862             :         }
     863             : 
     864             :         /* Find our DN */
     865             : 
     866          22 :         status = libnet_join_find_machine_acct(mem_ctx, r);
     867          22 :         if (!ADS_ERR_OK(status)) {
     868           0 :                 return status;
     869             :         }
     870             : 
     871          22 :         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          22 :         mods = ads_init_mods(mem_ctx);
     878          22 :         if (!mods) {
     879           0 :                 return ADS_ERROR(LDAP_NO_MEMORY);
     880             :         }
     881             : 
     882          22 :         status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
     883             :                              etype_list_str);
     884          22 :         if (!ADS_ERR_OK(status)) {
     885           0 :                 return status;
     886             :         }
     887             : 
     888          22 :         status = ads_gen_mod(r->in.ads, r->out.dn, mods);
     889          22 :         if (!ADS_ERR_OK(status)) {
     890           0 :                 return status;
     891             :         }
     892             : 
     893          22 :         r->out.set_encryption_types = r->in.desired_encryption_types;
     894             : 
     895          22 :         return ADS_SUCCESS;
     896             : }
     897             : 
     898             : /****************************************************************
     899             : ****************************************************************/
     900             : 
     901          26 : static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
     902             :                                       struct libnet_JoinCtx *r)
     903             : {
     904          26 :         if (!USE_SYSTEM_KEYTAB) {
     905          26 :                 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          26 : static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
     919             :                                                  struct libnet_JoinCtx *r)
     920             : {
     921             :         uint32_t domain_func;
     922             :         ADS_STATUS status;
     923          26 :         const char *salt = NULL;
     924          26 :         char *std_salt = NULL;
     925             : 
     926          26 :         status = ads_domain_func_level(r->in.ads, &domain_func);
     927          26 :         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          26 :         std_salt = kerberos_standard_des_salt();
     937          26 :         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          26 :         salt = talloc_strdup(mem_ctx, std_salt);
     944          26 :         if (!salt) {
     945           0 :                 return false;
     946             :         }
     947             : 
     948          26 :         SAFE_FREE(std_salt);
     949             : 
     950             :         /* if it's a Windows functional domain, we have to look for the UPN */
     951             : 
     952          26 :         if (domain_func == DS_DOMAIN_FUNCTION_2000) {
     953             :                 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          26 :         r->out.krb5_salt = salt;
     966          26 :         return true;
     967             : }
     968             : 
     969             : /****************************************************************
     970             : ****************************************************************/
     971             : 
     972          26 : static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
     973             :                                                          struct libnet_JoinCtx *r)
     974             : {
     975             :         ADS_STATUS status;
     976          26 :         bool need_etype_update = false;
     977             : 
     978          26 :         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           0 :                 return ADS_SUCCESS;
     984             :         }
     985             : 
     986          26 :         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          26 :         status = libnet_join_set_machine_spn(mem_ctx, r);
     994          26 :         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          26 :         status = libnet_join_set_os_attributes(mem_ctx, r);
    1004          26 :         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          26 :         status = libnet_join_set_machine_upn(mem_ctx, r);
    1012          26 :         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          26 :         status = libnet_join_find_machine_acct(mem_ctx, r);
    1020          26 :         if (!ADS_ERR_OK(status)) {
    1021           0 :                 return status;
    1022             :         }
    1023             : 
    1024          26 :         if (r->in.desired_encryption_types != r->out.set_encryption_types) {
    1025          24 :                 uint32_t func_level = 0;
    1026             : 
    1027          24 :                 status = ads_domain_func_level(r->in.ads, &func_level);
    1028          24 :                 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          24 :                 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
    1036          22 :                         need_etype_update = true;
    1037             :                 }
    1038             :         }
    1039             : 
    1040          26 :         if (need_etype_update) {
    1041             :                 /*
    1042             :                  * We need to reconnect as machine account in order
    1043             :                  * to update msDS-SupportedEncryptionTypes reliable
    1044             :                  */
    1045             : 
    1046          22 :                 if (r->in.ads->auth.ccache_name != NULL) {
    1047           8 :                         ads_kdestroy(r->in.ads->auth.ccache_name);
    1048           8 :                         TALLOC_FREE(r->in.ads->auth.ccache_name);
    1049             :                 }
    1050             : 
    1051          22 :                 TALLOC_FREE(r->in.ads);
    1052             : 
    1053          22 :                 status = libnet_join_connect_ads_machine(mem_ctx, r);
    1054          22 :                 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          22 :                 status = libnet_join_set_etypes(mem_ctx, r);
    1062          22 :                 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          26 :         if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
    1071           0 :                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
    1072             :         }
    1073             : 
    1074          26 :         return ADS_SUCCESS;
    1075             : }
    1076             : 
    1077          26 : static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
    1078             :                                                         struct libnet_JoinCtx *r)
    1079             : {
    1080          26 :         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          26 :         return ADS_SUCCESS;
    1087             : }
    1088             : #endif /* HAVE_ADS */
    1089             : 
    1090             : /****************************************************************
    1091             :  Store the machine password and domain SID
    1092             : ****************************************************************/
    1093             : 
    1094          27 : static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
    1095             :                                                  struct libnet_JoinCtx *r)
    1096             : {
    1097             :         NTSTATUS status;
    1098             : 
    1099          27 :         status = secrets_store_JoinCtx(r);
    1100          27 :         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          27 :         return true;
    1107             : }
    1108             : 
    1109             : /****************************************************************
    1110             :  Connect dc's IPC$ share
    1111             : ****************************************************************/
    1112             : 
    1113          28 : 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          28 :         TALLOC_CTX *frame = talloc_stackframe();
    1121          28 :         bool fallback_after_kerberos = false;
    1122          28 :         bool use_ccache = false;
    1123          28 :         bool pw_nt_hash = false;
    1124          28 :         struct cli_credentials *creds = NULL;
    1125          28 :         int flags = CLI_FULL_CONNECTION_IPC;
    1126             :         NTSTATUS status;
    1127             : 
    1128          28 :         if (use_kerberos && pass) {
    1129          16 :                 fallback_after_kerberos = true;
    1130             :         }
    1131             : 
    1132          28 :         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          28 :         if (creds == NULL) {
    1142           0 :                 TALLOC_FREE(frame);
    1143           0 :                 return NT_STATUS_NO_MEMORY;
    1144             :         }
    1145             : 
    1146          28 :         status = cli_full_connection_creds(cli,
    1147             :                                            NULL,
    1148             :                                            dc,
    1149             :                                            NULL, 0,
    1150             :                                            "IPC$", "IPC",
    1151             :                                            creds,
    1152             :                                            flags);
    1153          28 :         if (!NT_STATUS_IS_OK(status)) {
    1154           0 :                 TALLOC_FREE(frame);
    1155           0 :                 return status;
    1156             :         }
    1157             : 
    1158          28 :         TALLOC_FREE(frame);
    1159          28 :         return NT_STATUS_OK;
    1160             : }
    1161             : 
    1162             : /****************************************************************
    1163             :  Lookup domain dc's info
    1164             : ****************************************************************/
    1165             : 
    1166          28 : static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
    1167             :                                           struct libnet_JoinCtx *r,
    1168             :                                           struct cli_state **cli)
    1169             : {
    1170          28 :         struct rpc_pipe_client *pipe_hnd = NULL;
    1171             :         struct policy_handle lsa_pol;
    1172             :         NTSTATUS status, result;
    1173          28 :         union lsa_PolicyInformation *info = NULL;
    1174             :         struct dcerpc_binding_handle *b;
    1175          28 :         const char *account = r->in.admin_account;
    1176          28 :         const char *domain = r->in.admin_domain;
    1177          28 :         const char *password = r->in.admin_password;
    1178          28 :         bool use_kerberos = r->in.use_kerberos;
    1179             : 
    1180          28 :         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
    1181           1 :                 account = "";
    1182           1 :                 domain = "";
    1183           1 :                 password = NULL;
    1184           1 :                 use_kerberos = false;
    1185             :         }
    1186             : 
    1187          28 :         status = libnet_join_connect_dc_ipc(r->in.dc_name,
    1188             :                                             account,
    1189             :                                             domain,
    1190             :                                             password,
    1191             :                                             use_kerberos,
    1192             :                                             cli);
    1193          28 :         if (!NT_STATUS_IS_OK(status)) {
    1194           0 :                 goto done;
    1195             :         }
    1196             : 
    1197          28 :         status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
    1198             :                                           &pipe_hnd);
    1199          28 :         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          28 :         b = pipe_hnd->binding_handle;
    1206             : 
    1207          28 :         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
    1208             :                                         SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
    1209          28 :         if (!NT_STATUS_IS_OK(status)) {
    1210           0 :                 goto done;
    1211             :         }
    1212             : 
    1213          28 :         status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
    1214             :                                              &lsa_pol,
    1215             :                                              LSA_POLICY_INFO_DNS,
    1216             :                                              &info,
    1217             :                                              &result);
    1218          28 :         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
    1219          26 :                 r->out.domain_is_ad = true;
    1220          26 :                 r->out.netbios_domain_name = info->dns.name.string;
    1221          26 :                 r->out.dns_domain_name = info->dns.dns_domain.string;
    1222          26 :                 r->out.forest_name = info->dns.dns_forest.string;
    1223          26 :                 r->out.domain_guid = info->dns.domain_guid;
    1224          26 :                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
    1225          26 :                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
    1226             :         }
    1227             : 
    1228          28 :         if (!NT_STATUS_IS_OK(status)) {
    1229           2 :                 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
    1230             :                                                     &lsa_pol,
    1231             :                                                     LSA_POLICY_INFO_ACCOUNT_DOMAIN,
    1232             :                                                     &info,
    1233             :                                                     &result);
    1234           2 :                 if (!NT_STATUS_IS_OK(status)) {
    1235           0 :                         goto done;
    1236             :                 }
    1237           2 :                 if (!NT_STATUS_IS_OK(result)) {
    1238           0 :                         status = result;
    1239           0 :                         goto done;
    1240             :                 }
    1241             : 
    1242           2 :                 r->out.netbios_domain_name = info->account_domain.name.string;
    1243           2 :                 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
    1244           2 :                 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
    1245             :         }
    1246             : 
    1247          28 :         dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
    1248          45 :         TALLOC_FREE(pipe_hnd);
    1249             : 
    1250          17 :  done:
    1251          28 :         return status;
    1252             : }
    1253             : 
    1254             : /****************************************************************
    1255             :  Do the domain join unsecure
    1256             : ****************************************************************/
    1257             : 
    1258           1 : static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
    1259             :                                                     struct libnet_JoinCtx *r,
    1260             :                                                     struct cli_state *cli)
    1261             : {
    1262           1 :         TALLOC_CTX *frame = talloc_stackframe();
    1263           1 :         struct rpc_pipe_client *authenticate_pipe = NULL;
    1264           1 :         struct rpc_pipe_client *passwordset_pipe = NULL;
    1265             :         struct cli_credentials *cli_creds;
    1266           1 :         struct netlogon_creds_cli_context *netlogon_creds = NULL;
    1267           1 :         struct netlogon_creds_CredentialState *creds = NULL;
    1268           1 :         uint32_t netlogon_flags = 0;
    1269           1 :         size_t len = 0;
    1270             :         bool ok;
    1271           1 :         DATA_BLOB new_trust_blob = data_blob_null;
    1272             :         NTSTATUS status;
    1273             : 
    1274           1 :         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
    1275             :                                           &authenticate_pipe);
    1276           1 :         if (!NT_STATUS_IS_OK(status)) {
    1277           0 :                 TALLOC_FREE(frame);
    1278           0 :                 return status;
    1279             :         }
    1280             : 
    1281           1 :         if (!r->in.machine_password) {
    1282           1 :                 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
    1283             : 
    1284           1 :                 r->in.machine_password = trust_pw_new_value(mem_ctx,
    1285             :                                                 r->in.secure_channel_type,
    1286             :                                                 security);
    1287           1 :                 if (r->in.machine_password == NULL) {
    1288           0 :                         TALLOC_FREE(frame);
    1289           0 :                         return NT_STATUS_NO_MEMORY;
    1290             :                 }
    1291             :         }
    1292             : 
    1293           1 :         cli_creds = cli_credentials_init(talloc_tos());
    1294           1 :         if (cli_creds == NULL) {
    1295           0 :                 TALLOC_FREE(frame);
    1296           0 :                 return NT_STATUS_NO_MEMORY;
    1297             :         }
    1298             : 
    1299           1 :         cli_credentials_set_username(cli_creds, r->out.account_name,
    1300             :                                      CRED_SPECIFIED);
    1301           1 :         cli_credentials_set_domain(cli_creds, r->in.domain_name,
    1302             :                                    CRED_SPECIFIED);
    1303           1 :         cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
    1304           1 :         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           1 :         cli_credentials_set_password(cli_creds, r->in.admin_password,
    1309             :                                      CRED_SPECIFIED);
    1310             : 
    1311           2 :         status = rpccli_create_netlogon_creds_ctx(
    1312           1 :                 cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
    1313             :                 frame, &netlogon_creds);
    1314           1 :         if (!NT_STATUS_IS_OK(status)) {
    1315           0 :                 TALLOC_FREE(frame);
    1316           0 :                 return status;
    1317             :         }
    1318             : 
    1319           1 :         status = rpccli_setup_netlogon_creds(
    1320             :                 cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
    1321             :                 cli_creds);
    1322           1 :         if (!NT_STATUS_IS_OK(status)) {
    1323           1 :                 TALLOC_FREE(frame);
    1324           1 :                 return status;
    1325             :         }
    1326             : 
    1327           0 :         status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
    1328           0 :         if (!NT_STATUS_IS_OK(status)) {
    1329           0 :                 TALLOC_FREE(frame);
    1330           0 :                 return status;
    1331             :         }
    1332             : 
    1333           0 :         netlogon_flags = creds->negotiate_flags;
    1334           0 :         TALLOC_FREE(creds);
    1335             : 
    1336           0 :         if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
    1337           0 :                 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
    1338           0 :                 const struct sockaddr_storage *remote_sockaddr =
    1339           0 :                         smbXcli_conn_remote_sockaddr(cli->conn);
    1340             : 
    1341           0 :                 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           0 :                 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           0 :         len = strlen(r->in.machine_password);
    1358           0 :         ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
    1359           0 :                                    r->in.machine_password, len,
    1360             :                                    (void **)&new_trust_blob.data,
    1361             :                                    &new_trust_blob.length);
    1362           0 :         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           0 :         status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
    1372           0 :                                                       passwordset_pipe->binding_handle,
    1373             :                                                       &new_trust_blob,
    1374             :                                                       NULL); /* new_version */
    1375           0 :         if (!NT_STATUS_IS_OK(status)) {
    1376           0 :                 TALLOC_FREE(frame);
    1377           0 :                 return status;
    1378             :         }
    1379             : 
    1380           0 :         TALLOC_FREE(frame);
    1381           0 :         return NT_STATUS_OK;
    1382             : }
    1383             : 
    1384             : /****************************************************************
    1385             :  Do the domain join
    1386             : ****************************************************************/
    1387             : 
    1388           1 : static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
    1389             :                                            struct libnet_JoinCtx *r,
    1390             :                                            struct cli_state *cli)
    1391             : {
    1392           1 :         struct rpc_pipe_client *pipe_hnd = NULL;
    1393             :         struct policy_handle sam_pol, domain_pol, user_pol;
    1394           1 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
    1395             :         char *acct_name;
    1396             :         struct lsa_String lsa_acct_name;
    1397           1 :         uint32_t acct_flags = ACB_WSTRUST;
    1398             :         struct samr_Ids user_rids;
    1399             :         struct samr_Ids name_types;
    1400             :         union samr_UserInfo user_info;
    1401           1 :         struct dcerpc_binding_handle *b = NULL;
    1402           1 :         unsigned int old_timeout = 0;
    1403             : 
    1404           1 :         DATA_BLOB session_key = data_blob_null;
    1405             :         struct samr_CryptPassword crypt_pwd;
    1406             :         struct samr_CryptPasswordEx crypt_pwd_ex;
    1407             : 
    1408           1 :         ZERO_STRUCT(sam_pol);
    1409           1 :         ZERO_STRUCT(domain_pol);
    1410           1 :         ZERO_STRUCT(user_pol);
    1411             : 
    1412           1 :         switch (r->in.secure_channel_type) {
    1413           1 :         case SEC_CHAN_WKSTA:
    1414           1 :                 acct_flags = ACB_WSTRUST;
    1415           1 :                 break;
    1416           0 :         case SEC_CHAN_BDC:
    1417           0 :                 acct_flags = ACB_SVRTRUST;
    1418           0 :                 break;
    1419           0 :         default:
    1420           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1421             :         }
    1422             : 
    1423           1 :         if (!r->in.machine_password) {
    1424           1 :                 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
    1425             : 
    1426           1 :                 r->in.machine_password = trust_pw_new_value(mem_ctx,
    1427             :                                                 r->in.secure_channel_type,
    1428             :                                                 security);
    1429           1 :                 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
    1430             :         }
    1431             : 
    1432             :         /* Open the domain */
    1433             : 
    1434           1 :         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
    1435             :                                           &pipe_hnd);
    1436           1 :         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           1 :         b = pipe_hnd->binding_handle;
    1443             : 
    1444           1 :         status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
    1445           1 :         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           1 :         status = dcerpc_samr_Connect2(b, mem_ctx,
    1452           1 :                                       pipe_hnd->desthost,
    1453             :                                       SAMR_ACCESS_ENUM_DOMAINS
    1454             :                                       | SAMR_ACCESS_LOOKUP_DOMAIN,
    1455             :                                       &sam_pol,
    1456             :                                       &result);
    1457           1 :         if (!NT_STATUS_IS_OK(status)) {
    1458           0 :                 goto done;
    1459             :         }
    1460           1 :         if (!NT_STATUS_IS_OK(result)) {
    1461           0 :                 status = result;
    1462           0 :                 goto done;
    1463             :         }
    1464             : 
    1465           1 :         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           1 :         if (!NT_STATUS_IS_OK(status)) {
    1474           0 :                 goto done;
    1475             :         }
    1476           1 :         if (!NT_STATUS_IS_OK(result)) {
    1477           0 :                 status = result;
    1478           0 :                 goto done;
    1479             :         }
    1480             : 
    1481             :         /* Create domain user */
    1482             : 
    1483           1 :         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
    1484           1 :         if (!strlower_m(acct_name)) {
    1485           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1486           0 :                 goto done;
    1487             :         }
    1488             : 
    1489           1 :         init_lsa_String(&lsa_acct_name, acct_name);
    1490             : 
    1491           1 :         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
    1492           1 :                 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           1 :                 uint32_t access_granted = 0;
    1499             : 
    1500           1 :                 DEBUG(10,("Creating account with desired access mask: %d\n",
    1501             :                         access_desired));
    1502             : 
    1503           1 :                 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           1 :                 if (!NT_STATUS_IS_OK(status)) {
    1513           0 :                         goto done;
    1514             :                 }
    1515             : 
    1516           1 :                 status = result;
    1517           1 :                 if (!NT_STATUS_IS_OK(status) &&
    1518           0 :                     !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           1 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
    1537           0 :                         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           1 :                 if (NT_STATUS_IS_OK(status)) {
    1546           1 :                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
    1547             :                 }
    1548             :         }
    1549             : 
    1550           1 :         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           1 :         if (!NT_STATUS_IS_OK(status)) {
    1558           0 :                 goto done;
    1559             :         }
    1560           1 :         if (!NT_STATUS_IS_OK(result)) {
    1561           0 :                 status = result;
    1562           0 :                 goto done;
    1563             :         }
    1564           1 :         if (user_rids.count != 1) {
    1565           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    1566           0 :                 goto done;
    1567             :         }
    1568           1 :         if (name_types.count != 1) {
    1569           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    1570           0 :                 goto done;
    1571             :         }
    1572             : 
    1573           1 :         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           1 :         r->out.account_rid = user_rids.ids[0];
    1581             : 
    1582             :         /* Open handle on user */
    1583             : 
    1584           1 :         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           1 :         if (!NT_STATUS_IS_OK(status)) {
    1591           0 :                 goto done;
    1592             :         }
    1593           1 :         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           1 :         acct_flags |= ACB_PWNOEXP;
    1601             : 
    1602             :         /* Set account flags on machine account */
    1603           1 :         ZERO_STRUCT(user_info.info16);
    1604           1 :         user_info.info16.acct_flags = acct_flags;
    1605             : 
    1606           1 :         status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
    1607             :                                           &user_pol,
    1608             :                                           UserControlInformation,
    1609             :                                           &user_info,
    1610             :                                           &result);
    1611           1 :         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           1 :         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           1 :         old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
    1642             : 
    1643           1 :         status = init_samr_CryptPasswordEx(r->in.machine_password,
    1644             :                                            &session_key,
    1645             :                                            &crypt_pwd_ex);
    1646           1 :         if (!NT_STATUS_IS_OK(status)) {
    1647           0 :                 goto error;
    1648             :         }
    1649             : 
    1650           1 :         user_info.info26.password = crypt_pwd_ex;
    1651           1 :         user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
    1652             : 
    1653           1 :         status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
    1654             :                                           &user_pol,
    1655             :                                           UserInternal5InformationNew,
    1656             :                                           &user_info,
    1657             :                                           &result);
    1658             : 
    1659           1 :         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           2 : error:
    1681           1 :         old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
    1682             : 
    1683           1 :         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           1 :         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           1 :         status = NT_STATUS_OK;
    1708             : 
    1709           1 :  done:
    1710           1 :         if (!pipe_hnd) {
    1711           0 :                 return status;
    1712             :         }
    1713             : 
    1714           1 :         data_blob_clear_free(&session_key);
    1715             : 
    1716           1 :         if (is_valid_policy_hnd(&sam_pol)) {
    1717           1 :                 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
    1718             :         }
    1719           1 :         if (is_valid_policy_hnd(&domain_pol)) {
    1720           1 :                 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
    1721             :         }
    1722           1 :         if (is_valid_policy_hnd(&user_pol)) {
    1723           1 :                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
    1724             :         }
    1725           1 :         TALLOC_FREE(pipe_hnd);
    1726             : 
    1727           1 :         return status;
    1728             : }
    1729             : 
    1730             : /****************************************************************
    1731             : ****************************************************************/
    1732             : 
    1733          33 : 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          33 :         TALLOC_CTX *frame = talloc_stackframe();
    1739          33 :         struct cli_state *cli = NULL;
    1740          33 :         struct rpc_pipe_client *netlogon_pipe = NULL;
    1741          33 :         struct cli_credentials *cli_creds = NULL;
    1742          33 :         struct netlogon_creds_cli_context *netlogon_creds = NULL;
    1743          33 :         struct netlogon_creds_CredentialState *creds = NULL;
    1744          33 :         uint32_t netlogon_flags = 0;
    1745             :         NTSTATUS status;
    1746          33 :         int flags = CLI_FULL_CONNECTION_IPC;
    1747          33 :         const char *remote_name = NULL;
    1748          33 :         const struct sockaddr_storage *remote_sockaddr = NULL;
    1749             : 
    1750          33 :         if (!dc_name) {
    1751           0 :                 TALLOC_FREE(frame);
    1752           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1753             :         }
    1754             : 
    1755          33 :         if (!secrets_init()) {
    1756           0 :                 TALLOC_FREE(frame);
    1757           0 :                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
    1758             :         }
    1759             : 
    1760          33 :         status = pdb_get_trust_credentials(netbios_domain_name, NULL,
    1761             :                                            frame, &cli_creds);
    1762          33 :         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          33 :         cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
    1769             : 
    1770          33 :         if (use_kerberos) {
    1771          16 :                 cli_credentials_set_kerberos_state(cli_creds,
    1772             :                                                    CRED_USE_KERBEROS_REQUIRED,
    1773             :                                                    CRED_SPECIFIED);
    1774             :         }
    1775             : 
    1776          33 :         status = cli_full_connection_creds(&cli, NULL,
    1777             :                                            dc_name,
    1778             :                                            NULL, 0,
    1779             :                                            "IPC$", "IPC",
    1780             :                                            cli_creds,
    1781             :                                            flags);
    1782             : 
    1783          33 :         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          33 :         if (!NT_STATUS_IS_OK(status)) {
    1802           0 :                 TALLOC_FREE(frame);
    1803           0 :                 return status;
    1804             :         }
    1805             : 
    1806          33 :         status = rpccli_create_netlogon_creds_ctx(cli_creds,
    1807             :                                                   dc_name,
    1808             :                                                   msg_ctx,
    1809             :                                                   frame,
    1810             :                                                   &netlogon_creds);
    1811          33 :         if (!NT_STATUS_IS_OK(status)) {
    1812           0 :                 cli_shutdown(cli);
    1813           0 :                 TALLOC_FREE(frame);
    1814           0 :                 return status;
    1815             :         }
    1816             : 
    1817          33 :         status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
    1818             :                                              netlogon_creds,
    1819             :                                              true, /* force_reauth */
    1820             :                                              cli_creds);
    1821          33 :         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          33 :         status = netlogon_creds_cli_get(netlogon_creds,
    1833             :                                         talloc_tos(),
    1834             :                                         &creds);
    1835          33 :         if (!NT_STATUS_IS_OK(status)) {
    1836           0 :                 cli_shutdown(cli);
    1837           0 :                 TALLOC_FREE(frame);
    1838           0 :                 return status;
    1839             :         }
    1840          33 :         netlogon_flags = creds->negotiate_flags;
    1841          33 :         TALLOC_FREE(creds);
    1842             : 
    1843          33 :         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          33 :         remote_name = smbXcli_conn_remote_name(cli->conn);
    1850          33 :         remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
    1851             : 
    1852          33 :         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          33 :         TALLOC_FREE(netlogon_pipe);
    1860             : 
    1861          33 :         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          33 :         cli_shutdown(cli);
    1873          33 :         TALLOC_FREE(frame);
    1874          33 :         return NT_STATUS_OK;
    1875             : }
    1876             : 
    1877             : /****************************************************************
    1878             : ****************************************************************/
    1879             : 
    1880          27 : static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
    1881             :                                       struct libnet_JoinCtx *r)
    1882             : {
    1883             :         NTSTATUS status;
    1884             : 
    1885          27 :         status = libnet_join_ok(r->in.msg_ctx,
    1886             :                                 r->out.netbios_domain_name,
    1887             :                                 r->in.dc_name,
    1888          27 :                                 r->in.use_kerberos);
    1889          27 :         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          27 :         return WERR_OK;
    1897             : }
    1898             : 
    1899             : /****************************************************************
    1900             : ****************************************************************/
    1901             : 
    1902           0 : 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           0 :         return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
    1909             : }
    1910             : 
    1911             : /****************************************************************
    1912             : ****************************************************************/
    1913             : 
    1914           0 : static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
    1915             :                                              struct libnet_UnjoinCtx *r)
    1916             : {
    1917           0 :         struct cli_state *cli = NULL;
    1918           0 :         struct rpc_pipe_client *pipe_hnd = NULL;
    1919             :         struct policy_handle sam_pol, domain_pol, user_pol;
    1920           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
    1921             :         char *acct_name;
    1922             :         uint32_t user_rid;
    1923             :         struct lsa_String lsa_acct_name;
    1924             :         struct samr_Ids user_rids;
    1925             :         struct samr_Ids name_types;
    1926           0 :         union samr_UserInfo *info = NULL;
    1927           0 :         struct dcerpc_binding_handle *b = NULL;
    1928             : 
    1929           0 :         ZERO_STRUCT(sam_pol);
    1930           0 :         ZERO_STRUCT(domain_pol);
    1931           0 :         ZERO_STRUCT(user_pol);
    1932             : 
    1933           0 :         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           0 :                                             r->in.use_kerberos,
    1938             :                                             &cli);
    1939           0 :         if (!NT_STATUS_IS_OK(status)) {
    1940           0 :                 goto done;
    1941             :         }
    1942             : 
    1943             :         /* Open the domain */
    1944             : 
    1945           0 :         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
    1946             :                                           &pipe_hnd);
    1947           0 :         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           0 :         b = pipe_hnd->binding_handle;
    1954             : 
    1955           0 :         status = dcerpc_samr_Connect2(b, mem_ctx,
    1956           0 :                                       pipe_hnd->desthost,
    1957             :                                       SEC_FLAG_MAXIMUM_ALLOWED,
    1958             :                                       &sam_pol,
    1959             :                                       &result);
    1960           0 :         if (!NT_STATUS_IS_OK(status)) {
    1961           0 :                 goto done;
    1962             :         }
    1963           0 :         if (!NT_STATUS_IS_OK(result)) {
    1964           0 :                 status = result;
    1965           0 :                 goto done;
    1966             :         }
    1967             : 
    1968           0 :         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           0 :         if (!NT_STATUS_IS_OK(status)) {
    1975           0 :                 goto done;
    1976             :         }
    1977           0 :         if (!NT_STATUS_IS_OK(result)) {
    1978           0 :                 status = result;
    1979           0 :                 goto done;
    1980             :         }
    1981             : 
    1982             :         /* Create domain user */
    1983             : 
    1984           0 :         acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
    1985           0 :         if (!strlower_m(acct_name)) {
    1986           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1987           0 :                 goto done;
    1988             :         }
    1989             : 
    1990           0 :         init_lsa_String(&lsa_acct_name, acct_name);
    1991             : 
    1992           0 :         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           0 :         if (!NT_STATUS_IS_OK(status)) {
    2001           0 :                 goto done;
    2002             :         }
    2003           0 :         if (!NT_STATUS_IS_OK(result)) {
    2004           0 :                 status = result;
    2005           0 :                 goto done;
    2006             :         }
    2007           0 :         if (user_rids.count != 1) {
    2008           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2009           0 :                 goto done;
    2010             :         }
    2011           0 :         if (name_types.count != 1) {
    2012           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2013           0 :                 goto done;
    2014             :         }
    2015             : 
    2016           0 :         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           0 :         user_rid = user_rids.ids[0];
    2024             : 
    2025             :         /* Open handle on user */
    2026             : 
    2027           0 :         status = dcerpc_samr_OpenUser(b, mem_ctx,
    2028             :                                       &domain_pol,
    2029             :                                       SEC_FLAG_MAXIMUM_ALLOWED,
    2030             :                                       user_rid,
    2031             :                                       &user_pol,
    2032             :                                       &result);
    2033           0 :         if (!NT_STATUS_IS_OK(status)) {
    2034           0 :                 goto done;
    2035             :         }
    2036           0 :         if (!NT_STATUS_IS_OK(result)) {
    2037           0 :                 status = result;
    2038           0 :                 goto done;
    2039             :         }
    2040             : 
    2041             :         /* Get user info */
    2042             : 
    2043           0 :         status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
    2044             :                                            &user_pol,
    2045             :                                            16,
    2046             :                                            &info,
    2047             :                                            &result);
    2048           0 :         if (!NT_STATUS_IS_OK(status)) {
    2049           0 :                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
    2050           0 :                 goto done;
    2051             :         }
    2052           0 :         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           0 :         info->info16.acct_flags |= ACB_DISABLED;
    2061             : 
    2062           0 :         status = dcerpc_samr_SetUserInfo(b, mem_ctx,
    2063             :                                          &user_pol,
    2064             :                                          16,
    2065             :                                          info,
    2066             :                                          &result);
    2067           0 :         if (!NT_STATUS_IS_OK(status)) {
    2068           0 :                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
    2069           0 :                 goto done;
    2070             :         }
    2071           0 :         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           0 :         status = result;
    2077           0 :         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
    2078             : 
    2079           0 : done:
    2080           0 :         if (pipe_hnd && b) {
    2081           0 :                 if (is_valid_policy_hnd(&domain_pol)) {
    2082           0 :                         dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
    2083             :                 }
    2084           0 :                 if (is_valid_policy_hnd(&sam_pol)) {
    2085           0 :                         dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
    2086             :                 }
    2087           0 :                 TALLOC_FREE(pipe_hnd);
    2088             :         }
    2089             : 
    2090           0 :         if (cli) {
    2091           0 :                 cli_shutdown(cli);
    2092             :         }
    2093             : 
    2094           0 :         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             :         sbcErr err;
    2104             :         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             :         sbcErr err;
    2178             :         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          27 : static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
    2212             : {
    2213             :         WERROR werr;
    2214             : 
    2215          27 :         if (!W_ERROR_IS_OK(r->out.result)) {
    2216           0 :                 return r->out.result;
    2217             :         }
    2218             : 
    2219          27 :         if (!r->in.modify_config) {
    2220          27 :                 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           0 : static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
    2240             : {
    2241             :         WERROR werr;
    2242             : 
    2243           0 :         if (!W_ERROR_IS_OK(r->out.result)) {
    2244           0 :                 return r->out.result;
    2245             :         }
    2246             : 
    2247           0 :         if (!r->in.modify_config) {
    2248           0 :                 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          29 : 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          29 :         char *domain = NULL;
    2273          29 :         char *dc = NULL;
    2274          29 :         const char *p = NULL;
    2275             : 
    2276          29 :         if (!domain_str || !domain_p || !dc_p) {
    2277           0 :                 return false;
    2278             :         }
    2279             : 
    2280          29 :         p = strchr_m(domain_str, '\\');
    2281             : 
    2282          29 :         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          29 :                 domain = talloc_strdup(mem_ctx, domain_str);
    2291          29 :                 dc = NULL;
    2292             :         }
    2293          29 :         if (!domain) {
    2294           0 :                 return false;
    2295             :         }
    2296             : 
    2297          29 :         *domain_p = domain;
    2298             : 
    2299          29 :         if (!*dc_p && dc) {
    2300           0 :                 *dc_p = dc;
    2301             :         }
    2302             : 
    2303          29 :         return true;
    2304             : }
    2305             : 
    2306             : /****************************************************************
    2307             : ****************************************************************/
    2308             : 
    2309          29 : static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
    2310             :                                          struct libnet_JoinCtx *r)
    2311             : {
    2312          29 :         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          29 :         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          29 :         r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
    2328             :                                        r->in.machine_name);
    2329          29 :         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          29 :         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          29 :         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           0 :                 return WERR_OK;
    2349             :         }
    2350             : 
    2351          29 :         if (!r->in.admin_domain) {
    2352          28 :                 char *admin_domain = NULL;
    2353          28 :                 char *admin_account = NULL;
    2354             :                 bool ok;
    2355             : 
    2356          28 :                 ok = split_domain_user(mem_ctx,
    2357             :                                        r->in.admin_account,
    2358             :                                        &admin_domain,
    2359             :                                        &admin_account);
    2360          28 :                 if (!ok) {
    2361           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    2362             :                 }
    2363             : 
    2364          28 :                 if (admin_domain != NULL) {
    2365           0 :                         r->in.admin_domain = admin_domain;
    2366             :                 } else {
    2367          28 :                         r->in.admin_domain = r->in.domain_name;
    2368             :                 }
    2369          28 :                 r->in.admin_account = admin_account;
    2370             :         }
    2371             : 
    2372          29 :         if (!secrets_init()) {
    2373           0 :                 libnet_join_set_error_string(mem_ctx, r,
    2374             :                         "Unable to open secrets database");
    2375           0 :                 return WERR_CAN_NOT_COMPLETE;
    2376             :         }
    2377             : 
    2378          29 :         return WERR_OK;
    2379             : }
    2380             : 
    2381             : /****************************************************************
    2382             : ****************************************************************/
    2383             : 
    2384          27 : static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
    2385             : {
    2386             :         NTSTATUS status;
    2387             : 
    2388             :         /* Try adding dom admins to builtin\admins. Only log failures. */
    2389          27 :         status = create_builtin_administrators(domain_sid);
    2390          27 :         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
    2391          21 :                 DEBUG(10,("Unable to auto-add domain administrators to "
    2392             :                           "BUILTIN\\Administrators during join because "
    2393             :                           "winbindd must be running.\n"));
    2394           6 :         } else if (!NT_STATUS_IS_OK(status)) {
    2395           4 :                 DEBUG(5, ("Failed to auto-add domain administrators to "
    2396             :                           "BUILTIN\\Administrators during join: %s\n",
    2397             :                           nt_errstr(status)));
    2398             :         }
    2399             : 
    2400             :         /* Try adding dom users to builtin\users. Only log failures. */
    2401          27 :         status = create_builtin_users(domain_sid);
    2402          27 :         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
    2403          21 :                 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
    2404             :                           "during join because winbindd must be running.\n"));
    2405           6 :         } else if (!NT_STATUS_IS_OK(status)) {
    2406           4 :                 DEBUG(5, ("Failed to auto-add domain administrators to "
    2407             :                           "BUILTIN\\Administrators during join: %s\n",
    2408             :                           nt_errstr(status)));
    2409             :         }
    2410             : 
    2411             :         /* Try adding dom guests to builtin\guests. Only log failures. */
    2412          27 :         status = create_builtin_guests(domain_sid);
    2413          27 :         if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
    2414          21 :                 DEBUG(10,("Unable to auto-add domain guests to "
    2415             :                           "BUILTIN\\Guests during join because "
    2416             :                           "winbindd must be running.\n"));
    2417           6 :         } else if (!NT_STATUS_IS_OK(status)) {
    2418           4 :                 DEBUG(5, ("Failed to auto-add domain guests to "
    2419             :                           "BUILTIN\\Guests during join: %s\n",
    2420             :                           nt_errstr(status)));
    2421             :         }
    2422          27 : }
    2423             : 
    2424             : /****************************************************************
    2425             : ****************************************************************/
    2426             : 
    2427          27 : static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
    2428             :                                           struct libnet_JoinCtx *r)
    2429             : {
    2430             :         WERROR werr;
    2431             : 
    2432          27 :         if (!W_ERROR_IS_OK(r->out.result)) {
    2433           0 :                 return r->out.result;
    2434             :         }
    2435             : 
    2436          27 :         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
    2437           0 :                 werr = do_JoinConfig(r);
    2438           0 :                 if (!W_ERROR_IS_OK(werr)) {
    2439           0 :                         return werr;
    2440             :                 }
    2441             : 
    2442           0 :                 return WERR_OK;
    2443             :         }
    2444             : 
    2445             : #ifdef HAVE_ADS
    2446          42 :         if (r->out.domain_is_ad &&
    2447          26 :             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
    2448             :                 ADS_STATUS ads_status;
    2449             : 
    2450          26 :                 ads_status  = libnet_join_post_processing_ads_modify(mem_ctx, r);
    2451          26 :                 if (!ADS_ERR_OK(ads_status)) {
    2452           0 :                         return WERR_GEN_FAILURE;
    2453             :                 }
    2454             :         }
    2455             : #endif /* HAVE_ADS */
    2456             : 
    2457          27 :         if (r->in.provision_computer_account_only) {
    2458             :                 /*
    2459             :                  * When we only provision a computer account we are done here - gd.
    2460             :                  */
    2461           0 :                 return WERR_OK;
    2462             :         }
    2463             : 
    2464          27 :         saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
    2465          27 :         if (r->out.dns_domain_name) {
    2466          26 :                 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
    2467             :         }
    2468             : 
    2469          27 :         if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
    2470           0 :                 return WERR_NERR_SETUPNOTJOINED;
    2471             :         }
    2472             : 
    2473          27 :         werr = do_JoinConfig(r);
    2474          27 :         if (!W_ERROR_IS_OK(werr)) {
    2475           0 :                 return werr;
    2476             :         }
    2477             : 
    2478             : #ifdef HAVE_ADS
    2479          42 :         if (r->out.domain_is_ad &&
    2480          26 :             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
    2481             :                 ADS_STATUS ads_status;
    2482             : 
    2483          26 :                 ads_status  = libnet_join_post_processing_ads_sync(mem_ctx, r);
    2484          26 :                 if (!ADS_ERR_OK(ads_status)) {
    2485           0 :                         return WERR_GEN_FAILURE;
    2486             :                 }
    2487             :         }
    2488             : #endif /* HAVE_ADS */
    2489             : 
    2490          27 :         libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
    2491             : 
    2492          27 :         return WERR_OK;
    2493             : }
    2494             : 
    2495             : /****************************************************************
    2496             : ****************************************************************/
    2497             : 
    2498          28 : static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
    2499             : {
    2500          28 :         TALLOC_FREE(r->in.ads);
    2501             : 
    2502          28 :         return 0;
    2503             : }
    2504             : 
    2505             : /****************************************************************
    2506             : ****************************************************************/
    2507             : 
    2508           0 : static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
    2509             : {
    2510           0 :         TALLOC_FREE(r->in.ads);
    2511             : 
    2512           0 :         return 0;
    2513             : }
    2514             : 
    2515             : /****************************************************************
    2516             : ****************************************************************/
    2517             : 
    2518          28 : WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
    2519             :                            struct libnet_JoinCtx **r)
    2520             : {
    2521             :         struct libnet_JoinCtx *ctx;
    2522             : 
    2523          28 :         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
    2524          28 :         if (!ctx) {
    2525           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    2526             :         }
    2527             : 
    2528          28 :         talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
    2529             : 
    2530          28 :         ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
    2531          28 :         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
    2532             : 
    2533          28 :         ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
    2534             : 
    2535          28 :         ctx->in.desired_encryption_types = 0;
    2536          28 :         ctx->in.desired_encryption_types |= ENC_RC4_HMAC_MD5;
    2537          28 :         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
    2538          28 :         ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
    2539             : 
    2540          28 :         *r = ctx;
    2541             : 
    2542          28 :         return WERR_OK;
    2543             : }
    2544             : 
    2545             : /****************************************************************
    2546             : ****************************************************************/
    2547             : 
    2548           0 : WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
    2549             :                              struct libnet_UnjoinCtx **r)
    2550             : {
    2551             :         struct libnet_UnjoinCtx *ctx;
    2552             : 
    2553           0 :         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
    2554           0 :         if (!ctx) {
    2555           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    2556             :         }
    2557             : 
    2558           0 :         talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
    2559             : 
    2560           0 :         ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
    2561           0 :         W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
    2562             : 
    2563           0 :         *r = ctx;
    2564             : 
    2565           0 :         return WERR_OK;
    2566             : }
    2567             : 
    2568             : /****************************************************************
    2569             : ****************************************************************/
    2570             : 
    2571          28 : static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
    2572             :                                        struct libnet_JoinCtx *r)
    2573             : {
    2574          28 :         bool valid_security = false;
    2575          28 :         bool valid_workgroup = false;
    2576          28 :         bool valid_realm = false;
    2577          28 :         bool valid_hostname = false;
    2578          28 :         bool ignored_realm = false;
    2579             : 
    2580             :         /* check if configuration is already set correctly */
    2581             : 
    2582          28 :         valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
    2583          28 :         valid_hostname = strequal(lp_netbios_name(), r->in.machine_name);
    2584             : 
    2585          28 :         switch (r->out.domain_is_ad) {
    2586           2 :                 case false:
    2587           4 :                         valid_security = (lp_security() == SEC_DOMAIN)
    2588           0 :                                 || (lp_server_role() == ROLE_DOMAIN_PDC)
    2589           2 :                                 || (lp_server_role() == ROLE_DOMAIN_BDC);
    2590           2 :                         if (valid_workgroup && valid_security) {
    2591             :                                 /* nothing to be done */
    2592           2 :                                 return WERR_OK;
    2593             :                         }
    2594           0 :                         break;
    2595          26 :                 case true:
    2596          26 :                         valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
    2597          26 :                         switch (lp_security()) {
    2598           0 :                         case SEC_DOMAIN:
    2599           0 :                                 if (!valid_realm && lp_winbind_rpc_only()) {
    2600           0 :                                         valid_realm = true;
    2601           0 :                                         ignored_realm = true;
    2602             :                                 }
    2603             : 
    2604             :                                 FALL_THROUGH;
    2605             :                         case SEC_ADS:
    2606          26 :                                 valid_security = true;
    2607             :                         }
    2608             : 
    2609          26 :                         if (valid_workgroup && valid_realm && valid_security &&
    2610             :                                         valid_hostname) {
    2611          26 :                                 if (ignored_realm && !r->in.modify_config)
    2612             :                                 {
    2613           0 :                                         libnet_join_set_error_string(mem_ctx, r,
    2614             :                                                 "Warning: ignoring realm when "
    2615             :                                                 "joining AD domain with "
    2616             :                                                 "'security=domain' and "
    2617             :                                                 "'winbind rpc only = yes'. "
    2618             :                                                 "(realm set to '%s', "
    2619             :                                                 "should be '%s').", lp_realm(),
    2620             :                                                 r->out.dns_domain_name);
    2621             :                                 }
    2622             :                                 /* nothing to be done */
    2623          26 :                                 return WERR_OK;
    2624             :                         }
    2625           0 :                         break;
    2626             :         }
    2627             : 
    2628             :         /* check if we are supposed to manipulate configuration */
    2629             : 
    2630           0 :         if (!r->in.modify_config) {
    2631             : 
    2632           0 :                 char *wrong_conf = talloc_strdup(mem_ctx, "");
    2633             : 
    2634           0 :                 if (!valid_hostname) {
    2635           0 :                         wrong_conf = talloc_asprintf_append(wrong_conf,
    2636             :                                 "\"netbios name\" set to '%s', should be '%s'",
    2637             :                                 lp_netbios_name(), r->in.machine_name);
    2638           0 :                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
    2639             :                 }
    2640             : 
    2641           0 :                 if (!valid_workgroup) {
    2642           0 :                         wrong_conf = talloc_asprintf_append(wrong_conf,
    2643             :                                 "\"workgroup\" set to '%s', should be '%s'",
    2644             :                                 lp_workgroup(), r->out.netbios_domain_name);
    2645           0 :                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
    2646             :                 }
    2647             : 
    2648           0 :                 if (!valid_realm) {
    2649           0 :                         wrong_conf = talloc_asprintf_append(wrong_conf,
    2650             :                                 "\"realm\" set to '%s', should be '%s'",
    2651             :                                 lp_realm(), r->out.dns_domain_name);
    2652           0 :                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
    2653             :                 }
    2654             : 
    2655           0 :                 if (!valid_security) {
    2656           0 :                         const char *sec = NULL;
    2657           0 :                         switch (lp_security()) {
    2658           0 :                         case SEC_USER:  sec = "user"; break;
    2659           0 :                         case SEC_DOMAIN: sec = "domain"; break;
    2660           0 :                         case SEC_ADS: sec = "ads"; break;
    2661             :                         }
    2662           0 :                         wrong_conf = talloc_asprintf_append(wrong_conf,
    2663             :                                 "\"security\" set to '%s', should be %s",
    2664           0 :                                 sec, r->out.domain_is_ad ?
    2665             :                                 "either 'domain' or 'ads'" : "'domain'");
    2666           0 :                         W_ERROR_HAVE_NO_MEMORY(wrong_conf);
    2667             :                 }
    2668             : 
    2669           0 :                 libnet_join_set_error_string(mem_ctx, r,
    2670             :                         "Invalid configuration (%s) and configuration modification "
    2671             :                         "was not requested", wrong_conf);
    2672           0 :                 return WERR_CAN_NOT_COMPLETE;
    2673             :         }
    2674             : 
    2675             :         /* check if we are able to manipulate configuration */
    2676             : 
    2677           0 :         if (!lp_config_backend_is_registry()) {
    2678           0 :                 libnet_join_set_error_string(mem_ctx, r,
    2679             :                         "Configuration manipulation requested but not "
    2680             :                         "supported by backend");
    2681           0 :                 return WERR_NOT_SUPPORTED;
    2682             :         }
    2683             : 
    2684           0 :         return WERR_OK;
    2685             : }
    2686             : 
    2687             : /****************************************************************
    2688             : ****************************************************************/
    2689             : 
    2690          29 : static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
    2691             :                                 struct libnet_JoinCtx *r)
    2692             : {
    2693             :         NTSTATUS status;
    2694             :         WERROR werr;
    2695          29 :         struct cli_state *cli = NULL;
    2696             : #ifdef HAVE_ADS
    2697             :         ADS_STATUS ads_status;
    2698             : #endif /* HAVE_ADS */
    2699          29 :         const char *pre_connect_realm = NULL;
    2700          29 :         const char *sitename = NULL;
    2701             :         struct netr_DsRGetDCNameInfo *info;
    2702             :         const char *dc;
    2703          29 :         uint32_t name_type_flags = 0;
    2704             : 
    2705             :         /* Before contacting a DC, we can securely know
    2706             :          * the realm only if the user specifies it.
    2707             :          */
    2708          39 :         if (r->in.use_kerberos &&
    2709          16 :             r->in.domain_name_type == JoinDomNameTypeDNS) {
    2710          16 :                 pre_connect_realm = r->in.domain_name;
    2711             :         }
    2712             : 
    2713          29 :         if (r->in.domain_name_type == JoinDomNameTypeDNS) {
    2714          26 :                 name_type_flags = DS_IS_DNS_NAME;
    2715           3 :         } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
    2716           1 :                 name_type_flags = DS_IS_FLAT_NAME;
    2717             :         }
    2718             : 
    2719          29 :         if (r->in.dc_name) {
    2720           0 :                 status = dsgetonedcname(mem_ctx,
    2721             :                                         r->in.msg_ctx,
    2722             :                                         r->in.domain_name,
    2723             :                                         r->in.dc_name,
    2724             :                                         DS_DIRECTORY_SERVICE_REQUIRED |
    2725             :                                         DS_WRITABLE_REQUIRED |
    2726             :                                         DS_RETURN_DNS_NAME |
    2727             :                                         name_type_flags,
    2728             :                                         &info);
    2729             :         } else {
    2730          29 :                 status = dsgetdcname(mem_ctx,
    2731             :                                      r->in.msg_ctx,
    2732             :                                      r->in.domain_name,
    2733             :                                      NULL,
    2734             :                                      NULL,
    2735             :                                      DS_FORCE_REDISCOVERY |
    2736             :                                      DS_DIRECTORY_SERVICE_REQUIRED |
    2737             :                                      DS_WRITABLE_REQUIRED |
    2738             :                                      DS_RETURN_DNS_NAME |
    2739             :                                      name_type_flags,
    2740             :                                      &info);
    2741             :         }
    2742          29 :         if (!NT_STATUS_IS_OK(status)) {
    2743           1 :                 libnet_join_set_error_string(mem_ctx, r,
    2744             :                         "failed to find DC for domain %s - %s",
    2745             :                         r->in.domain_name,
    2746             :                         get_friendly_nt_error_msg(status));
    2747           1 :                 return WERR_NERR_DCNOTFOUND;
    2748             :         }
    2749             : 
    2750          28 :         dc = strip_hostname(info->dc_unc);
    2751          28 :         r->in.dc_name = talloc_strdup(mem_ctx, dc);
    2752          28 :         W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
    2753             : 
    2754          45 :         if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
    2755          28 :             info->dc_address[1] != '\\') {
    2756           0 :                 DBG_ERR("ill-formed DC address '%s'\n",
    2757             :                         info->dc_address);
    2758           0 :                 return WERR_NERR_DCNOTFOUND;
    2759             :         }
    2760             : 
    2761          28 :         sitename = info->dc_site_name;
    2762             :         /* info goes out of scope but the memory stays
    2763             :            allocated on the talloc context */
    2764             : 
    2765             :         /* return the allocated netr_DsRGetDCNameInfo struct */
    2766          28 :         r->out.dcinfo = info;
    2767             : 
    2768          28 :         if (pre_connect_realm != NULL) {
    2769          16 :                 struct sockaddr_storage ss = {0};
    2770          16 :                 const char *numeric_dcip = info->dc_address + 2;
    2771             : 
    2772          16 :                 if (numeric_dcip[0] == '\0') {
    2773           0 :                         if (!interpret_string_addr(&ss, numeric_dcip,
    2774             :                                                    AI_NUMERICHOST)) {
    2775           0 :                                 DBG_ERR(
    2776             :                                     "cannot parse IP address '%s' of DC '%s'\n",
    2777             :                                     numeric_dcip, r->in.dc_name);
    2778           0 :                                 return WERR_NERR_DCNOTFOUND;
    2779             :                         }
    2780             :                 } else {
    2781          16 :                         if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
    2782           0 :                                 DBG_WARNING(
    2783             :                                     "cannot resolve IP address of DC '%s'\n",
    2784             :                                     r->in.dc_name);
    2785           0 :                                 return WERR_NERR_DCNOTFOUND;
    2786             :                         }
    2787             :                 }
    2788             : 
    2789             :                 /* The domain parameter is only used as modifier
    2790             :                  * to krb5.conf file name. _JOIN_ is is not a valid
    2791             :                  * NetBIOS name so it cannot clash with another domain
    2792             :                  * -- Uri.
    2793             :                  */
    2794          16 :                 create_local_private_krb5_conf_for_domain(pre_connect_realm,
    2795             :                                                           "_JOIN_",
    2796             :                                                           sitename,
    2797             :                                                           &ss);
    2798             :         }
    2799             : 
    2800          28 :         status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
    2801          28 :         if (!NT_STATUS_IS_OK(status)) {
    2802           0 :                 libnet_join_set_error_string(mem_ctx, r,
    2803             :                         "failed to lookup DC info for domain '%s' over rpc: %s",
    2804             :                         r->in.domain_name, get_friendly_nt_error_msg(status));
    2805           0 :                 return ntstatus_to_werror(status);
    2806             :         }
    2807             : 
    2808          28 :         werr = libnet_join_check_config(mem_ctx, r);
    2809          28 :         if (!W_ERROR_IS_OK(werr)) {
    2810           0 :                 if (!r->in.provision_computer_account_only) {
    2811           0 :                         goto done;
    2812             :                 }
    2813             :                 /* do not fail when only provisioning */
    2814             :         }
    2815             : 
    2816             : #ifdef HAVE_ADS
    2817             : 
    2818          28 :         if (r->out.domain_is_ad) {
    2819          26 :                 create_local_private_krb5_conf_for_domain(
    2820             :                         r->out.dns_domain_name, r->out.netbios_domain_name,
    2821          26 :                         sitename, smbXcli_conn_remote_sockaddr(cli->conn));
    2822             :         }
    2823             : 
    2824          43 :         if (r->out.domain_is_ad &&
    2825          26 :             !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
    2826             : 
    2827          26 :                 const char *initial_account_ou = r->in.account_ou;
    2828             : 
    2829             :                 /*
    2830             :                  * we want to create the msDS-SupportedEncryptionTypes attribute
    2831             :                  * as early as possible so always try an LDAP create as the user
    2832             :                  * first. We copy r->in.account_ou because it may be changed
    2833             :                  * during the machine pre-creation.
    2834             :                  */
    2835             : 
    2836          26 :                 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
    2837          26 :                 if (!ADS_ERR_OK(ads_status)) {
    2838           0 :                         libnet_join_set_error_string(mem_ctx, r,
    2839             :                                 "failed to connect to AD: %s",
    2840             :                                 ads_errstr(ads_status));
    2841           0 :                         return WERR_NERR_DEFAULTJOINREQUIRED;
    2842             :                 }
    2843             : 
    2844          26 :                 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
    2845          26 :                 if (ADS_ERR_OK(ads_status)) {
    2846             : 
    2847             :                         /*
    2848             :                          * LDAP object creation succeeded.
    2849             :                          */
    2850          26 :                         r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
    2851             : 
    2852          26 :                         return WERR_OK;
    2853             :                 }
    2854             : 
    2855           0 :                 if (initial_account_ou != NULL) {
    2856           0 :                         libnet_join_set_error_string(mem_ctx, r,
    2857             :                                 "failed to precreate account in ou %s: %s",
    2858             :                                 r->in.account_ou,
    2859             :                                 ads_errstr(ads_status));
    2860           0 :                         return WERR_NERR_DEFAULTJOINREQUIRED;
    2861             :                 }
    2862             : 
    2863           0 :                 DBG_INFO("Failed to pre-create account in OU %s: %s\n",
    2864             :                          r->in.account_ou, ads_errstr(ads_status));
    2865             :         }
    2866             : #endif /* HAVE_ADS */
    2867             : 
    2868           3 :         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
    2869           1 :             (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
    2870           1 :                 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
    2871             :         } else {
    2872           1 :                 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
    2873             :         }
    2874           2 :         if (!NT_STATUS_IS_OK(status)) {
    2875           1 :                 libnet_join_set_error_string(mem_ctx, r,
    2876             :                         "failed to join domain '%s' over rpc: %s",
    2877             :                         r->in.domain_name, get_friendly_nt_error_msg(status));
    2878           1 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
    2879           0 :                         return WERR_NERR_SETUPALREADYJOINED;
    2880             :                 }
    2881           1 :                 werr = ntstatus_to_werror(status);
    2882           1 :                 goto done;
    2883             :         }
    2884             : 
    2885           1 :         werr = WERR_OK;
    2886             : 
    2887           2 :  done:
    2888           2 :         if (cli) {
    2889           2 :                 cli_shutdown(cli);
    2890             :         }
    2891             : 
    2892           2 :         return werr;
    2893             : }
    2894             : 
    2895             : /****************************************************************
    2896             : ****************************************************************/
    2897             : 
    2898           0 : static WERROR libnet_DomainOfflineJoin(TALLOC_CTX *mem_ctx,
    2899             :                                        struct libnet_JoinCtx *r)
    2900             : {
    2901             :         NTSTATUS status;
    2902             :         WERROR werr;
    2903             :         struct ODJ_WIN7BLOB win7blob;
    2904             :         struct OP_JOINPROV3_PART joinprov3;
    2905             :         const char *dc_name;
    2906             : 
    2907           0 :         if (!r->in.request_offline_join) {
    2908           0 :                 return WERR_NERR_DEFAULTJOINREQUIRED;
    2909             :         }
    2910             : 
    2911           0 :         if (r->in.odj_provision_data == NULL) {
    2912           0 :                 return WERR_INVALID_PARAMETER;
    2913             :         }
    2914             : 
    2915           0 :         werr = libnet_odj_find_win7blob(r->in.odj_provision_data, &win7blob);
    2916           0 :         if (!W_ERROR_IS_OK(werr)) {
    2917           0 :                 return werr;
    2918             :         }
    2919             : 
    2920           0 :         r->out.netbios_domain_name = talloc_strdup(mem_ctx,
    2921             :                         win7blob.DnsDomainInfo.Name.string);
    2922           0 :         W_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
    2923             : 
    2924           0 :         r->out.dns_domain_name = talloc_strdup(mem_ctx,
    2925             :                         win7blob.DnsDomainInfo.DnsDomainName.string);
    2926           0 :         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
    2927             : 
    2928           0 :         r->out.forest_name = talloc_strdup(mem_ctx,
    2929             :                         win7blob.DnsDomainInfo.DnsForestName.string);
    2930           0 :         W_ERROR_HAVE_NO_MEMORY(r->out.forest_name);
    2931             : 
    2932           0 :         r->out.domain_guid = win7blob.DnsDomainInfo.DomainGuid;
    2933           0 :         r->out.domain_sid = dom_sid_dup(mem_ctx,
    2934           0 :                         win7blob.DnsDomainInfo.Sid);
    2935           0 :         W_ERROR_HAVE_NO_MEMORY(r->out.domain_sid);
    2936             : 
    2937           0 :         werr = libnet_odj_find_joinprov3(r->in.odj_provision_data, &joinprov3);
    2938           0 :         if (!W_ERROR_IS_OK(werr)) {
    2939           0 :                 return werr;
    2940             :         }
    2941             : 
    2942           0 :         r->out.account_rid = joinprov3.Rid;
    2943             : 
    2944           0 :         dc_name = strip_hostname(win7blob.DcInfo.dc_address);
    2945           0 :         if (dc_name == NULL) {
    2946           0 :                 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
    2947             :         }
    2948           0 :         r->in.dc_name = talloc_strdup(mem_ctx, dc_name);
    2949           0 :         W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
    2950             : 
    2951           0 :         r->out.domain_is_ad = true;
    2952             : 
    2953             :         /* we cannot use talloc_steal but have to deep copy the struct here */
    2954           0 :         status = copy_netr_DsRGetDCNameInfo(mem_ctx, &win7blob.DcInfo,
    2955             :                                             &r->out.dcinfo);
    2956           0 :         if (!NT_STATUS_IS_OK(status)) {
    2957           0 :                 return ntstatus_to_werror(status);
    2958             :         }
    2959             : 
    2960           0 :         werr = libnet_join_check_config(mem_ctx, r);
    2961           0 :         if (!W_ERROR_IS_OK(werr)) {
    2962           0 :                 return werr;
    2963             :         }
    2964             : 
    2965           0 :         return WERR_OK;
    2966             : #if 0
    2967             :         /* the following fields are currently not filled in */
    2968             : 
    2969             :         const char * dn;
    2970             :         uint32_t set_encryption_types;
    2971             :         const char * krb5_salt;
    2972             : #endif
    2973             : }
    2974             : 
    2975             : /****************************************************************
    2976             : ****************************************************************/
    2977             : 
    2978           0 : static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
    2979             :                                    struct libnet_JoinCtx *r)
    2980             : {
    2981             :         WERROR werr;
    2982           0 :         struct libnet_UnjoinCtx *u = NULL;
    2983             : 
    2984           0 :         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
    2985           0 :         if (!W_ERROR_IS_OK(werr)) {
    2986           0 :                 return werr;
    2987             :         }
    2988             : 
    2989           0 :         u->in.debug          = r->in.debug;
    2990           0 :         u->in.dc_name                = r->in.dc_name;
    2991           0 :         u->in.domain_name    = r->in.domain_name;
    2992           0 :         u->in.admin_account  = r->in.admin_account;
    2993           0 :         u->in.admin_password = r->in.admin_password;
    2994           0 :         u->in.modify_config  = r->in.modify_config;
    2995           0 :         u->in.use_kerberos   = r->in.use_kerberos;
    2996           0 :         u->in.unjoin_flags   = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
    2997             :                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
    2998             : 
    2999           0 :         werr = libnet_Unjoin(mem_ctx, u);
    3000           0 :         TALLOC_FREE(u);
    3001             : 
    3002           0 :         return werr;
    3003             : }
    3004             : 
    3005             : /****************************************************************
    3006             : ****************************************************************/
    3007             : 
    3008          29 : WERROR libnet_Join(TALLOC_CTX *mem_ctx,
    3009             :                    struct libnet_JoinCtx *r)
    3010             : {
    3011             :         WERROR werr;
    3012             : 
    3013          29 :         if (r->in.debug) {
    3014          23 :                 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
    3015             :         }
    3016             : 
    3017          29 :         ZERO_STRUCT(r->out);
    3018             : 
    3019          29 :         werr = libnet_join_pre_processing(mem_ctx, r);
    3020          29 :         if (!W_ERROR_IS_OK(werr)) {
    3021           0 :                 goto done;
    3022             :         }
    3023             : 
    3024          29 :         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
    3025          29 :                 if (r->in.request_offline_join) {
    3026           0 :                         werr = libnet_DomainOfflineJoin(mem_ctx, r);
    3027             :                 } else {
    3028          29 :                         werr = libnet_DomainJoin(mem_ctx, r);
    3029             :                 }
    3030          29 :                 if (!W_ERROR_IS_OK(werr)) {
    3031           2 :                         goto done;
    3032             :                 }
    3033             :         }
    3034             : 
    3035          27 :         werr = libnet_join_post_processing(mem_ctx, r);
    3036          27 :         if (!W_ERROR_IS_OK(werr)) {
    3037           0 :                 goto done;
    3038             :         }
    3039             : 
    3040          27 :         if (r->in.provision_computer_account_only) {
    3041             :                 /*
    3042             :                  * When we only provision a computer account we are done here - gd.
    3043             :                  */
    3044           0 :                 goto done;
    3045             :         }
    3046             : 
    3047          27 :         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
    3048          27 :                 if (r->in.request_offline_join) {
    3049             :                         /*
    3050             :                          * When we are serving an offline domain join request we
    3051             :                          * have no network so we are done here - gd.
    3052             :                          */
    3053           0 :                         goto done;
    3054             :                 }
    3055             : 
    3056          27 :                 werr = libnet_join_post_verify(mem_ctx, r);
    3057          27 :                 if (!W_ERROR_IS_OK(werr)) {
    3058           0 :                         libnet_join_rollback(mem_ctx, r);
    3059             :                 }
    3060             :         }
    3061             : 
    3062          44 :  done:
    3063          29 :         r->out.result = werr;
    3064             : 
    3065          29 :         if (r->in.debug) {
    3066          23 :                 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
    3067             :         }
    3068          29 :         return werr;
    3069             : }
    3070             : 
    3071             : /****************************************************************
    3072             : ****************************************************************/
    3073             : 
    3074           0 : static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
    3075             :                                   struct libnet_UnjoinCtx *r)
    3076             : {
    3077             :         NTSTATUS status;
    3078             : 
    3079           0 :         if (!r->in.domain_sid) {
    3080             :                 struct dom_sid sid;
    3081           0 :                 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
    3082           0 :                         libnet_unjoin_set_error_string(mem_ctx, r,
    3083             :                                 "Unable to fetch domain sid: are we joined?");
    3084           0 :                         return WERR_NERR_SETUPNOTJOINED;
    3085             :                 }
    3086           0 :                 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
    3087           0 :                 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
    3088             :         }
    3089             : 
    3090           0 :         if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
    3091           0 :             !r->in.delete_machine_account) {
    3092           0 :                 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
    3093           0 :                 return WERR_OK;
    3094             :         }
    3095             : 
    3096           0 :         if (!r->in.dc_name) {
    3097             :                 struct netr_DsRGetDCNameInfo *info;
    3098             :                 const char *dc;
    3099           0 :                 status = dsgetdcname(mem_ctx,
    3100             :                                      r->in.msg_ctx,
    3101             :                                      r->in.domain_name,
    3102             :                                      NULL,
    3103             :                                      NULL,
    3104             :                                      DS_DIRECTORY_SERVICE_REQUIRED |
    3105             :                                      DS_WRITABLE_REQUIRED |
    3106             :                                      DS_RETURN_DNS_NAME,
    3107             :                                      &info);
    3108           0 :                 if (!NT_STATUS_IS_OK(status)) {
    3109           0 :                         libnet_unjoin_set_error_string(mem_ctx, r,
    3110             :                                 "failed to find DC for domain %s - %s",
    3111             :                                 r->in.domain_name,
    3112             :                                 get_friendly_nt_error_msg(status));
    3113           0 :                         return WERR_NERR_DCNOTFOUND;
    3114             :                 }
    3115             : 
    3116           0 :                 dc = strip_hostname(info->dc_unc);
    3117           0 :                 r->in.dc_name = talloc_strdup(mem_ctx, dc);
    3118           0 :                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
    3119             :         }
    3120             : 
    3121             : #ifdef HAVE_ADS
    3122             :         /* for net ads leave, try to delete the account.  If it works,
    3123             :            no sense in disabling.  If it fails, we can still try to
    3124             :            disable it. jmcd */
    3125             : 
    3126           0 :         if (r->in.delete_machine_account) {
    3127             :                 ADS_STATUS ads_status;
    3128           0 :                 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
    3129           0 :                 if (ADS_ERR_OK(ads_status)) {
    3130             :                         /* dirty hack */
    3131           0 :                         r->out.dns_domain_name =
    3132           0 :                                 talloc_strdup(mem_ctx,
    3133           0 :                                               r->in.ads->server.realm);
    3134           0 :                         ads_status =
    3135           0 :                                 libnet_unjoin_remove_machine_acct(mem_ctx, r);
    3136             :                 }
    3137           0 :                 if (!ADS_ERR_OK(ads_status)) {
    3138           0 :                         libnet_unjoin_set_error_string(mem_ctx, r,
    3139             :                                 "failed to remove machine account from AD: %s",
    3140             :                                 ads_errstr(ads_status));
    3141             :                 } else {
    3142           0 :                         r->out.deleted_machine_account = true;
    3143           0 :                         W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
    3144           0 :                         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
    3145           0 :                         return WERR_OK;
    3146             :                 }
    3147             :         }
    3148             : #endif /* HAVE_ADS */
    3149             : 
    3150             :         /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
    3151             :            "disable".  */
    3152           0 :         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
    3153           0 :                 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
    3154           0 :                 if (!NT_STATUS_IS_OK(status)) {
    3155           0 :                         libnet_unjoin_set_error_string(mem_ctx, r,
    3156             :                                 "failed to disable machine account via rpc: %s",
    3157             :                                 get_friendly_nt_error_msg(status));
    3158           0 :                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
    3159           0 :                                 return WERR_NERR_SETUPNOTJOINED;
    3160             :                         }
    3161           0 :                         return ntstatus_to_werror(status);
    3162             :                 }
    3163             : 
    3164           0 :                 r->out.dns_domain_name = talloc_strdup(mem_ctx,
    3165             :                                                       r->in.domain_name);
    3166           0 :                 r->out.disabled_machine_account = true;
    3167             :         }
    3168             : 
    3169             :         /* If disable succeeded or was not requested at all, we
    3170             :            should be getting rid of our end of things */
    3171             : 
    3172           0 :         libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
    3173             : 
    3174           0 :         return WERR_OK;
    3175             : }
    3176             : 
    3177             : /****************************************************************
    3178             : ****************************************************************/
    3179             : 
    3180           0 : static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
    3181             :                                            struct libnet_UnjoinCtx *r)
    3182             : {
    3183           0 :         if (!r->in.domain_name) {
    3184           0 :                 libnet_unjoin_set_error_string(mem_ctx, r,
    3185             :                         "No domain name defined");
    3186           0 :                 return WERR_INVALID_PARAMETER;
    3187             :         }
    3188             : 
    3189           0 :         if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
    3190             :                                     &r->in.domain_name,
    3191             :                                     &r->in.dc_name)) {
    3192           0 :                 libnet_unjoin_set_error_string(mem_ctx, r,
    3193             :                         "Failed to parse domain name");
    3194           0 :                 return WERR_INVALID_PARAMETER;
    3195             :         }
    3196             : 
    3197           0 :         if (IS_DC) {
    3198           0 :                 return WERR_NERR_SETUPDOMAINCONTROLLER;
    3199             :         }
    3200             : 
    3201           0 :         if (!r->in.admin_domain) {
    3202           0 :                 char *admin_domain = NULL;
    3203           0 :                 char *admin_account = NULL;
    3204             :                 bool ok;
    3205             : 
    3206           0 :                 ok = split_domain_user(mem_ctx,
    3207             :                                        r->in.admin_account,
    3208             :                                        &admin_domain,
    3209             :                                        &admin_account);
    3210           0 :                 if (!ok) {
    3211           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    3212             :                 }
    3213             : 
    3214           0 :                 if (admin_domain != NULL) {
    3215           0 :                         r->in.admin_domain = admin_domain;
    3216             :                 } else {
    3217           0 :                         r->in.admin_domain = r->in.domain_name;
    3218             :                 }
    3219           0 :                 r->in.admin_account = admin_account;
    3220             :         }
    3221             : 
    3222           0 :         if (!secrets_init()) {
    3223           0 :                 libnet_unjoin_set_error_string(mem_ctx, r,
    3224             :                         "Unable to open secrets database");
    3225           0 :                 return WERR_CAN_NOT_COMPLETE;
    3226             :         }
    3227             : 
    3228           0 :         return WERR_OK;
    3229             : }
    3230             : 
    3231             : /****************************************************************
    3232             : ****************************************************************/
    3233             : 
    3234           0 : static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
    3235             :                                             struct libnet_UnjoinCtx *r)
    3236             : {
    3237           0 :         saf_delete(r->out.netbios_domain_name);
    3238           0 :         saf_delete(r->out.dns_domain_name);
    3239             : 
    3240           0 :         return libnet_unjoin_config(r);
    3241             : }
    3242             : 
    3243             : /****************************************************************
    3244             : ****************************************************************/
    3245             : 
    3246           0 : WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
    3247             :                      struct libnet_UnjoinCtx *r)
    3248             : {
    3249             :         WERROR werr;
    3250             : 
    3251           0 :         if (r->in.debug) {
    3252           0 :                 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
    3253             :         }
    3254             : 
    3255           0 :         werr = libnet_unjoin_pre_processing(mem_ctx, r);
    3256           0 :         if (!W_ERROR_IS_OK(werr)) {
    3257           0 :                 goto done;
    3258             :         }
    3259             : 
    3260           0 :         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
    3261           0 :                 werr = libnet_DomainUnjoin(mem_ctx, r);
    3262           0 :                 if (!W_ERROR_IS_OK(werr)) {
    3263           0 :                         libnet_unjoin_config(r);
    3264           0 :                         goto done;
    3265             :                 }
    3266             :         }
    3267             : 
    3268           0 :         werr = libnet_unjoin_post_processing(mem_ctx, r);
    3269           0 :         if (!W_ERROR_IS_OK(werr)) {
    3270           0 :                 goto done;
    3271             :         }
    3272             : 
    3273           0 :  done:
    3274           0 :         r->out.result = werr;
    3275             : 
    3276           0 :         if (r->in.debug) {
    3277           0 :                 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
    3278             :         }
    3279             : 
    3280           0 :         return werr;
    3281             : }

Generated by: LCOV version 1.13