LCOV - code coverage report
Current view: top level - source4/libnet - libnet_join.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 313 592 52.9 %
Date: 2024-06-10 12:05:21 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    
       4             :    Copyright (C) Stefan Metzmacher      2004
       5             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       6             :    Copyright (C) Brad Henry 2005
       7             :  
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libnet/libnet.h"
      24             : #include "libnet/libnet_join_proto.h"
      25             : #include "librpc/gen_ndr/ndr_drsuapi_c.h"
      26             : #include <ldb.h>
      27             : #include <ldb_errors.h>
      28             : #include "dsdb/samdb/samdb.h"
      29             : #include "ldb_wrap.h"
      30             : #include "libcli/security/security.h"
      31             : #include "auth/credentials/credentials.h"
      32             : #include "auth/credentials/credentials_krb5.h"
      33             : #include "librpc/gen_ndr/ndr_samr_c.h"
      34             : #include "param/param.h"
      35             : #include "param/provision.h"
      36             : #include "system/kerberos.h"
      37             : #include "auth/kerberos/kerberos.h"
      38             : 
      39             : /*
      40             :  * complete a domain join, when joining to a AD domain:
      41             :  * 1.) connect and bind to the DRSUAPI pipe
      42             :  * 2.) do a DsCrackNames() to find the machine account dn
      43             :  * 3.) connect to LDAP
      44             :  * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account
      45             :  * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...)
      46             :  * 6.) do a DsCrackNames() to find the domain dn
      47             :  * 7.) find out Site specific stuff, look at libnet_JoinSite() for details
      48             :  */
      49         507 : static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r)
      50             : {
      51         403 :         NTSTATUS status;
      52             : 
      53         403 :         TALLOC_CTX *tmp_ctx;
      54             : 
      55         507 :         const char *realm = r->out.realm;
      56             : 
      57         507 :         const struct dcerpc_binding *samr_binding = r->out.samr_binding;
      58             : 
      59         403 :         struct dcerpc_pipe *drsuapi_pipe;
      60         403 :         struct dcerpc_binding *drsuapi_binding;
      61         403 :         enum dcerpc_transport_t transport;
      62         403 :         struct drsuapi_DsBind r_drsuapi_bind;
      63         403 :         struct drsuapi_DsCrackNames r_crack_names;
      64         403 :         struct drsuapi_DsNameString names[1];
      65         403 :         struct policy_handle drsuapi_bind_handle;
      66         403 :         struct GUID drsuapi_bind_guid;
      67             : 
      68         403 :         struct ldb_context *remote_ldb;
      69         403 :         struct ldb_dn *account_dn;
      70         403 :         const char *account_dn_str;
      71         403 :         const char *remote_ldb_url;
      72         403 :         struct ldb_result *res;
      73         403 :         struct ldb_message *msg;
      74             : 
      75         403 :         int ret, rtn;
      76             : 
      77         507 :         const char * const attrs[] = {
      78             :                 "msDS-KeyVersionNumber",
      79             :                 "servicePrincipalName",
      80             :                 "dNSHostName",
      81             :                 "objectGUID",
      82             :                 NULL,
      83             :         };
      84             : 
      85         507 :         r->out.error_string = NULL;
      86             :         
      87             :         /* We need to convert between a samAccountName and domain to a
      88             :          * DN in the directory.  The correct way to do this is with
      89             :          * DRSUAPI CrackNames */
      90             : 
      91             :         /* Fiddle with the bindings, so get to DRSUAPI on
      92             :          * NCACN_IP_TCP, sealed */
      93         507 :         tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context");  
      94         507 :         if (!tmp_ctx) {
      95           0 :                 r->out.error_string = NULL;
      96           0 :                 return NT_STATUS_NO_MEMORY;
      97             :         }
      98             : 
      99         507 :         drsuapi_binding = dcerpc_binding_dup(tmp_ctx, samr_binding);
     100         507 :         if (!drsuapi_binding) {
     101           0 :                 r->out.error_string = NULL;
     102           0 :                 talloc_free(tmp_ctx);
     103           0 :                 return NT_STATUS_NO_MEMORY;
     104             :         }
     105             : 
     106         507 :         transport = dcerpc_binding_get_transport(drsuapi_binding);
     107             : 
     108             :         /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */
     109         507 :         if (transport != NCALRPC) {
     110         447 :                 status = dcerpc_binding_set_transport(drsuapi_binding, NCACN_IP_TCP);
     111         447 :                 if (!NT_STATUS_IS_OK(status)) {
     112           0 :                         r->out.error_string = talloc_asprintf(r,
     113             :                                                 "dcerpc_binding_set_transport failed: %s",
     114             :                                                 nt_errstr(status));
     115           0 :                         talloc_free(tmp_ctx);
     116           0 :                         return status;
     117             :                 }
     118             :         }
     119             : 
     120         507 :         status = dcerpc_binding_set_string_option(drsuapi_binding, "endpoint", NULL);
     121         507 :         if (!NT_STATUS_IS_OK(status)) {
     122           0 :                 r->out.error_string = talloc_asprintf(r,
     123             :                                         "dcerpc_binding_set_string_option failed: %s",
     124             :                                         nt_errstr(status));
     125           0 :                 talloc_free(tmp_ctx);
     126           0 :                 return status;
     127             :         }
     128             : 
     129         507 :         status = dcerpc_binding_set_flags(drsuapi_binding, DCERPC_SEAL, 0);
     130         507 :         if (!NT_STATUS_IS_OK(status)) {
     131           0 :                 r->out.error_string = talloc_asprintf(r,
     132             :                                         "dcerpc_binding_set_flags failed: %s",
     133             :                                         nt_errstr(status));
     134           0 :                 talloc_free(tmp_ctx);
     135           0 :                 return status;
     136             :         }
     137             : 
     138         507 :         status = dcerpc_pipe_connect_b(tmp_ctx, 
     139             :                                        &drsuapi_pipe,
     140             :                                        drsuapi_binding,
     141             :                                        &ndr_table_drsuapi,
     142             :                                        ctx->cred, 
     143             :                                        ctx->event_ctx,
     144             :                                        ctx->lp_ctx);
     145         507 :         if (!NT_STATUS_IS_OK(status)) {
     146           0 :                 r->out.error_string = talloc_asprintf(r,
     147             :                                         "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s",
     148             :                                         r->out.domain_name,
     149             :                                         nt_errstr(status));
     150           0 :                 talloc_free(tmp_ctx);
     151           0 :                 return status;
     152             :         }
     153             : 
     154             :         /* get a DRSUAPI pipe handle */
     155         507 :         GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid);
     156             : 
     157         507 :         r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid;
     158         507 :         r_drsuapi_bind.in.bind_info = NULL;
     159         507 :         r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle;
     160             : 
     161         507 :         status = dcerpc_drsuapi_DsBind_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_drsuapi_bind);
     162         507 :         if (!NT_STATUS_IS_OK(status)) {
     163           0 :                 r->out.error_string
     164           0 :                         = talloc_asprintf(r,
     165             :                                           "dcerpc_drsuapi_DsBind failed - %s",
     166             :                                           nt_errstr(status));
     167           0 :                 talloc_free(tmp_ctx);
     168           0 :                 return status;
     169         507 :         } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) {
     170           0 :                 r->out.error_string
     171           0 :                                 = talloc_asprintf(r,
     172             :                                                   "DsBind failed - %s", 
     173             :                                                   win_errstr(r_drsuapi_bind.out.result));
     174           0 :                         talloc_free(tmp_ctx);
     175           0 :                 return NT_STATUS_UNSUCCESSFUL;
     176             :         }
     177             : 
     178             :         /* Actually 'crack' the names */
     179         507 :         ZERO_STRUCT(r_crack_names);
     180         507 :         r_crack_names.in.bind_handle            = &drsuapi_bind_handle;
     181         507 :         r_crack_names.in.level                  = 1;
     182         507 :         r_crack_names.in.req                    = talloc(r, union drsuapi_DsNameRequest);
     183         507 :         if (!r_crack_names.in.req) {
     184           0 :                 r->out.error_string = NULL;
     185           0 :                 talloc_free(tmp_ctx);
     186           0 :                 return NT_STATUS_NO_MEMORY;
     187             :         }
     188         507 :         r_crack_names.in.req->req1.codepage  = 1252; /* western european */
     189         507 :         r_crack_names.in.req->req1.language  = 0x00000407; /* german */
     190         507 :         r_crack_names.in.req->req1.count     = 1;
     191         507 :         r_crack_names.in.req->req1.names     = names;
     192         507 :         r_crack_names.in.req->req1.format_flags      = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
     193         507 :         r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
     194         507 :         r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
     195         507 :         names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid);
     196         507 :         if (!names[0].str) {
     197           0 :                 r->out.error_string = NULL;
     198           0 :                 talloc_free(tmp_ctx);
     199           0 :                 return NT_STATUS_NO_MEMORY;
     200             :         }
     201             : 
     202         507 :         r_crack_names.out.ctr                   = talloc(r, union drsuapi_DsNameCtr);
     203         507 :         r_crack_names.out.level_out             = talloc(r, uint32_t);
     204         507 :         if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) {
     205           0 :                 r->out.error_string = NULL;
     206           0 :                 talloc_free(tmp_ctx);
     207           0 :                 return NT_STATUS_NO_MEMORY;
     208             :         }
     209             : 
     210         507 :         status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names);
     211         507 :         if (!NT_STATUS_IS_OK(status)) {
     212           0 :                 r->out.error_string
     213           0 :                         = talloc_asprintf(r,
     214             :                                           "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s",
     215             :                                           names[0].str,
     216             :                                           nt_errstr(status));
     217           0 :                 talloc_free(tmp_ctx);
     218           0 :                 return status;
     219         507 :         } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
     220           0 :                 r->out.error_string
     221           0 :                                 = talloc_asprintf(r,
     222             :                                                   "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
     223           0 :                 talloc_free(tmp_ctx);
     224           0 :                 return NT_STATUS_UNSUCCESSFUL;
     225         507 :         } else if (*r_crack_names.out.level_out != 1
     226         507 :                    || !r_crack_names.out.ctr->ctr1
     227         507 :                    || r_crack_names.out.ctr->ctr1->count != 1) {
     228           0 :                 r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
     229           0 :                 talloc_free(tmp_ctx);
     230           0 :                 return NT_STATUS_INVALID_PARAMETER;
     231         507 :         } else if (r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
     232           0 :                 r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr->ctr1->array[0].status);
     233           0 :                 talloc_free(tmp_ctx);
     234           0 :                 return NT_STATUS_UNSUCCESSFUL;
     235         507 :         } else if (r_crack_names.out.ctr->ctr1->array[0].result_name == NULL) {
     236           0 :                 r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name");
     237           0 :                 talloc_free(tmp_ctx);
     238           0 :                 return NT_STATUS_INVALID_PARAMETER;
     239             :         }
     240             : 
     241             :         /* Store the DN of our machine account. */
     242         507 :         account_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name;
     243             : 
     244             :         /* Now we know the user's DN, open with LDAP, read and modify a few things */
     245             : 
     246         507 :         remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", 
     247             :                 dcerpc_binding_get_string_option(drsuapi_binding, "target_hostname"));
     248         507 :         if (!remote_ldb_url) {
     249           0 :                 r->out.error_string = NULL;
     250           0 :                 talloc_free(tmp_ctx);
     251           0 :                 return NT_STATUS_NO_MEMORY;
     252             :         }
     253             : 
     254         507 :         remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx,
     255             :                                       remote_ldb_url, 
     256             :                                       NULL, ctx->cred, 0);
     257         507 :         if (!remote_ldb) {
     258           0 :                 r->out.error_string = NULL;
     259           0 :                 talloc_free(tmp_ctx);
     260           0 :                 return NT_STATUS_UNSUCCESSFUL;
     261             :         }
     262             : 
     263         507 :         account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);
     264         507 :         if (account_dn == NULL) {
     265           0 :                 r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
     266             :                                                       account_dn_str);
     267           0 :                 talloc_free(tmp_ctx);
     268           0 :                 return NT_STATUS_UNSUCCESSFUL;
     269             :         }
     270             : 
     271             :         /* search for the user's record */
     272         507 :         ret = ldb_search(remote_ldb, tmp_ctx, &res,
     273             :                          account_dn, LDB_SCOPE_BASE, attrs, NULL);
     274         507 :         if (ret != LDB_SUCCESS) {
     275           0 :                 r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s",
     276             :                                                       account_dn_str, ldb_errstring(remote_ldb));
     277           0 :                 talloc_free(tmp_ctx);
     278           0 :                 return NT_STATUS_UNSUCCESSFUL;
     279             :         }
     280             : 
     281         507 :         if (res->count != 1) {
     282           0 :                 r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries",
     283           0 :                                                       account_dn_str, res->count);
     284           0 :                 talloc_free(tmp_ctx);
     285           0 :                 return NT_STATUS_UNSUCCESSFUL;
     286             :         }
     287             : 
     288             :         /* Prepare a new message, for the modify */
     289         507 :         msg = ldb_msg_new(tmp_ctx);
     290         507 :         if (!msg) {
     291           0 :                 r->out.error_string = NULL;
     292           0 :                 talloc_free(tmp_ctx);
     293           0 :                 return NT_STATUS_NO_MEMORY;
     294             :         }
     295         507 :         msg->dn = res->msgs[0]->dn;
     296             : 
     297             :         {
     298         403 :                 unsigned int i;
     299         403 :                 const char *service_principal_name[2];
     300         611 :                 const char *dns_host_name = strlower_talloc(msg,
     301         507 :                                                             talloc_asprintf(msg, 
     302             :                                                                             "%s.%s", 
     303             :                                                                             r->in.netbios_name, 
     304             :                                                                             realm));
     305             : 
     306         507 :                 if (!dns_host_name) {
     307           0 :                         r->out.error_string = NULL;
     308           0 :                         talloc_free(tmp_ctx);
     309           0 :                         return NT_STATUS_NO_MEMORY;
     310             :                 }
     311             : 
     312         507 :                 service_principal_name[0] = talloc_asprintf(msg, "HOST/%s",
     313             :                                                             dns_host_name);
     314         507 :                 service_principal_name[1] = talloc_asprintf(msg, "HOST/%s",
     315             :                                                             r->in.netbios_name);
     316             :                 
     317        1521 :                 for (i=0; i < ARRAY_SIZE(service_principal_name); i++) {
     318        1014 :                         if (!service_principal_name[i]) {
     319           0 :                                 r->out.error_string = NULL;
     320           0 :                                 talloc_free(tmp_ctx);
     321           0 :                                 return NT_STATUS_NO_MEMORY;
     322             :                         }
     323        1014 :                         rtn = ldb_msg_add_string(msg, "servicePrincipalName",
     324             :                                                  service_principal_name[i]);
     325        1014 :                         if (rtn != LDB_SUCCESS) {
     326           0 :                                 r->out.error_string = NULL;
     327           0 :                                 talloc_free(tmp_ctx);
     328           0 :                                 return NT_STATUS_NO_MEMORY;
     329             :                         }
     330             :                 }
     331             : 
     332         507 :                 rtn = ldb_msg_add_string(msg, "dNSHostName", dns_host_name);
     333         507 :                 if (rtn != LDB_SUCCESS) {
     334           0 :                         r->out.error_string = NULL;
     335           0 :                         talloc_free(tmp_ctx);
     336           0 :                         return NT_STATUS_NO_MEMORY;
     337             :                 }
     338             : 
     339         507 :                 rtn = dsdb_replace(remote_ldb, msg, 0);
     340         507 :                 if (rtn != LDB_SUCCESS) {
     341           0 :                         r->out.error_string
     342           0 :                                 = talloc_asprintf(r, 
     343             :                                                   "Failed to replace entries on %s", 
     344             :                                                   ldb_dn_get_linearized(msg->dn));
     345           0 :                         talloc_free(tmp_ctx);
     346           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     347             :                 }
     348             :         }
     349             :                                 
     350         507 :         msg = ldb_msg_new(tmp_ctx);
     351         507 :         if (!msg) {
     352           0 :                 r->out.error_string = NULL;
     353           0 :                 talloc_free(tmp_ctx);
     354           0 :                 return NT_STATUS_NO_MEMORY;
     355             :         }
     356         507 :         msg->dn = res->msgs[0]->dn;
     357             : 
     358         507 :         rtn = samdb_msg_add_uint(remote_ldb, msg, msg,
     359             :                                  "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES);
     360         507 :         if (rtn != LDB_SUCCESS) {
     361           0 :                 r->out.error_string = NULL;
     362           0 :                 talloc_free(tmp_ctx);
     363           0 :                 return NT_STATUS_NO_MEMORY;
     364             :         }
     365             : 
     366         507 :         rtn = dsdb_replace(remote_ldb, msg, 0);
     367             :         /* The remote server may not support this attribute, if it
     368             :          * isn't a modern schema */
     369         507 :         if (rtn != LDB_SUCCESS && rtn != LDB_ERR_NO_SUCH_ATTRIBUTE) {
     370           0 :                 r->out.error_string
     371           0 :                         = talloc_asprintf(r,
     372             :                                           "Failed to replace msDS-SupportedEncryptionTypes on %s",
     373             :                                           ldb_dn_get_linearized(msg->dn));
     374           0 :                 talloc_free(tmp_ctx);
     375           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     376             :         }
     377             : 
     378             :         /* DsCrackNames to find out the DN of the domain. */
     379         507 :         r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
     380         507 :         r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
     381         507 :         names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name);
     382         507 :         if (!names[0].str) {
     383           0 :                 r->out.error_string = NULL;
     384           0 :                 talloc_free(tmp_ctx);
     385           0 :                 return NT_STATUS_NO_MEMORY;
     386             :         }
     387             : 
     388         507 :         status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names);
     389         507 :         if (!NT_STATUS_IS_OK(status)) {
     390           0 :                 r->out.error_string
     391           0 :                         = talloc_asprintf(r,
     392             :                                           "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s",
     393             :                                           r->in.domain_name,
     394             :                                           nt_errstr(status));
     395           0 :                 talloc_free(tmp_ctx);
     396           0 :                 return status;
     397         507 :         } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
     398           0 :                 r->out.error_string
     399           0 :                         = talloc_asprintf(r,
     400             :                                           "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
     401           0 :                 talloc_free(tmp_ctx);
     402           0 :                 return NT_STATUS_UNSUCCESSFUL;
     403         507 :         } else if (*r_crack_names.out.level_out != 1
     404         507 :                    || !r_crack_names.out.ctr->ctr1
     405         507 :                    || r_crack_names.out.ctr->ctr1->count != 1
     406         507 :                    || !r_crack_names.out.ctr->ctr1->array[0].result_name
     407         507 :                    || r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
     408           0 :                 r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
     409           0 :                 talloc_free(tmp_ctx);
     410           0 :                 return NT_STATUS_UNSUCCESSFUL;
     411             :         }
     412             : 
     413             :         /* Store the account DN. */
     414         507 :         r->out.account_dn_str = account_dn_str;
     415         507 :         talloc_steal(r, account_dn_str);
     416             : 
     417             :         /* Store the domain DN. */
     418         507 :         r->out.domain_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name;
     419         507 :         talloc_steal(r, r_crack_names.out.ctr->ctr1->array[0].result_name);
     420             : 
     421             :         /* Store the KVNO of the account, critical for some kerberos
     422             :          * operations */
     423         507 :         r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);
     424             : 
     425             :         /* Store the account GUID. */
     426         507 :         r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID");
     427             : 
     428         507 :         if (r->in.acct_type == ACB_SVRTRUST) {
     429         239 :                 status = libnet_JoinSite(ctx, remote_ldb, r);
     430             :         }
     431         507 :         talloc_free(tmp_ctx);
     432             : 
     433         507 :         return status;
     434             : }
     435             : 
     436             : /*
     437             :  * do a domain join using DCERPC/SAMR calls
     438             :  * - connect to the LSA pipe, to try and find out information about the domain
     439             :  * - create a secondary connection to SAMR pipe
     440             :  * - do a samr_Connect to get a policy handle
     441             :  * - do a samr_LookupDomain to get the domain sid
     442             :  * - do a samr_OpenDomain to get a domain handle
     443             :  * - do a samr_CreateAccount to try and get a new account 
     444             :  * 
     445             :  * If that fails, do:
     446             :  * - do a samr_LookupNames to get the users rid
     447             :  * - do a samr_OpenUser to get a user handle
     448             :  * - potentially delete and recreate the user
     449             :  * - assert the account is of the right type with samrQueryUserInfo
     450             :  * 
     451             :  * - call libnet_SetPassword_samr_handle to set the password,
     452             :  *   and pass a samr_UserInfo21 struct to set full_name and the account flags
     453             :  *
     454             :  * - do some ADS specific things when we join as Domain Controller,
     455             :  *    look at libnet_joinADSDomain() for the details
     456             :  */
     457         559 : NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r)
     458             : {
     459         454 :         TALLOC_CTX *tmp_ctx;
     460             : 
     461         454 :         NTSTATUS status, cu_status;
     462             : 
     463         454 :         struct libnet_RpcConnect *connect_with_info;
     464         454 :         struct dcerpc_pipe *samr_pipe;
     465             : 
     466         454 :         struct samr_Connect sc;
     467         454 :         struct policy_handle p_handle;
     468         454 :         struct samr_OpenDomain od;
     469         454 :         struct policy_handle d_handle;
     470         454 :         struct samr_LookupNames ln;
     471         454 :         struct samr_Ids rids, types;
     472         454 :         struct samr_OpenUser ou;
     473         454 :         struct samr_CreateUser2 cu;
     474         559 :         struct policy_handle *u_handle = NULL;
     475         454 :         struct samr_QueryUserInfo qui;
     476         454 :         union samr_UserInfo *uinfo;
     477         454 :         struct samr_UserInfo21 u_info21;
     478         454 :         union libnet_SetPassword r2;
     479         454 :         struct samr_GetUserPwInfo pwp;
     480         454 :         struct samr_PwInfo info;
     481         454 :         struct lsa_String samr_account_name;
     482             :         
     483         454 :         uint32_t acct_flags, old_acct_flags;
     484         454 :         uint32_t rid, access_granted;
     485         559 :         int policy_min_pw_len = 0;
     486             : 
     487         559 :         struct dom_sid *account_sid = NULL;
     488         559 :         const char *password_str = NULL;
     489             :         
     490         559 :         r->out.error_string = NULL;
     491         559 :         ZERO_STRUCT(r2);
     492             : 
     493         559 :         tmp_ctx = talloc_named(mem_ctx, 0, "libnet_Join temp context");
     494         559 :         if (!tmp_ctx) {
     495           0 :                 r->out.error_string = NULL;
     496           0 :                 return NT_STATUS_NO_MEMORY;
     497             :         }
     498             :         
     499         559 :         u_handle = talloc(tmp_ctx, struct policy_handle);
     500         559 :         if (!u_handle) {
     501           0 :                 r->out.error_string = NULL;
     502           0 :                 talloc_free(tmp_ctx);
     503           0 :                 return NT_STATUS_NO_MEMORY;
     504             :         }
     505             :         
     506         559 :         connect_with_info = talloc_zero(tmp_ctx, struct libnet_RpcConnect);
     507         559 :         if (!connect_with_info) {
     508           0 :                 r->out.error_string = NULL;
     509           0 :                 talloc_free(tmp_ctx);
     510           0 :                 return NT_STATUS_NO_MEMORY;
     511             :         }
     512             : 
     513             :         /* prepare connect to the SAMR pipe of PDC */
     514         559 :         if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
     515          13 :                 connect_with_info->in.binding = NULL;
     516          13 :                 connect_with_info->in.name    = r->in.domain_name;
     517             :         } else {
     518         546 :                 connect_with_info->in.binding = r->in.binding;
     519         546 :                 connect_with_info->in.name    = NULL;
     520             :         }
     521             : 
     522             :         /* This level makes a connection to the LSA pipe on the way,
     523             :          * to get some useful bits of information about the domain */
     524         559 :         connect_with_info->level              = LIBNET_RPC_CONNECT_DC_INFO;
     525         559 :         connect_with_info->in.dcerpc_iface    = &ndr_table_samr;
     526             : 
     527             :         /*
     528             :           establish the SAMR connection
     529             :         */
     530         559 :         status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info);
     531         559 :         if (!NT_STATUS_IS_OK(status)) {
     532           2 :                 if (r->in.binding) {
     533           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     534             :                                                               "Connection to SAMR pipe of DC %s failed: %s",
     535             :                                                               r->in.binding, connect_with_info->out.error_string);
     536             :                 } else {
     537           2 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     538             :                                                               "Connection to SAMR pipe of PDC for %s failed: %s",
     539             :                                                               r->in.domain_name, connect_with_info->out.error_string);
     540             :                 }
     541           2 :                 talloc_free(tmp_ctx);
     542           2 :                 return status;
     543             :         }
     544             : 
     545         557 :         samr_pipe = connect_with_info->out.dcerpc_pipe;
     546             : 
     547             :         /* prepare samr_Connect */
     548         557 :         ZERO_STRUCT(p_handle);
     549         557 :         sc.in.system_name = NULL;
     550         557 :         sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
     551         557 :         sc.out.connect_handle = &p_handle;
     552             : 
     553             :         /* 2. do a samr_Connect to get a policy handle */
     554         557 :         status = dcerpc_samr_Connect_r(samr_pipe->binding_handle, tmp_ctx, &sc);
     555         557 :         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sc.out.result)) {
     556           0 :                 status = sc.out.result;
     557             :         }
     558         557 :         if (!NT_STATUS_IS_OK(status)) {
     559           0 :                 r->out.error_string = talloc_asprintf(mem_ctx,
     560             :                                                 "samr_Connect failed: %s",
     561             :                                                 nt_errstr(status));
     562           0 :                 talloc_free(tmp_ctx);
     563           0 :                 return status;
     564             :         }
     565             : 
     566             :         /* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */
     567         557 :         if (!connect_with_info->out.domain_name) {
     568           0 :                 if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
     569           0 :                         connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name);
     570             :                 } else {
     571             :                         /* Bugger, we just lost our way to automatically find the domain name */
     572           0 :                         connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lpcfg_workgroup(ctx->lp_ctx));
     573           0 :                         connect_with_info->out.realm = talloc_strdup(tmp_ctx, lpcfg_realm(ctx->lp_ctx));
     574             :                 }
     575             :         }
     576             : 
     577             :         /* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */
     578         557 :         if (!connect_with_info->out.domain_sid) {
     579           0 :                 struct lsa_String name;
     580           0 :                 struct samr_LookupDomain l;
     581           0 :                 struct dom_sid2 *sid = NULL;
     582           0 :                 name.string = connect_with_info->out.domain_name;
     583           0 :                 l.in.connect_handle = &p_handle;
     584           0 :                 l.in.domain_name = &name;
     585           0 :                 l.out.sid = &sid;
     586             :                 
     587           0 :                 status = dcerpc_samr_LookupDomain_r(samr_pipe->binding_handle, tmp_ctx, &l);
     588           0 :                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(l.out.result)) {
     589           0 :                         status = l.out.result;
     590             :                 }
     591           0 :                 if (!NT_STATUS_IS_OK(status)) {
     592           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     593             :                                                               "SAMR LookupDomain failed: %s",
     594             :                                                               nt_errstr(status));
     595           0 :                         talloc_free(tmp_ctx);
     596           0 :                         return status;
     597             :                 }
     598           0 :                 connect_with_info->out.domain_sid = *l.out.sid;
     599             :         }
     600             : 
     601             :         /* prepare samr_OpenDomain */
     602         557 :         ZERO_STRUCT(d_handle);
     603         557 :         od.in.connect_handle = &p_handle;
     604         557 :         od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
     605         557 :         od.in.sid = connect_with_info->out.domain_sid;
     606         557 :         od.out.domain_handle = &d_handle;
     607             : 
     608             :         /* do a samr_OpenDomain to get a domain handle */
     609         557 :         status = dcerpc_samr_OpenDomain_r(samr_pipe->binding_handle, tmp_ctx, &od);
     610         557 :         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(od.out.result)) {
     611           0 :                 status = od.out.result;
     612             :         }
     613         557 :         if (!NT_STATUS_IS_OK(status)) {
     614           0 :                 struct dom_sid_buf buf;
     615           0 :                 r->out.error_string = talloc_asprintf(
     616             :                         mem_ctx,
     617             :                         "samr_OpenDomain for [%s] failed: %s",
     618           0 :                         dom_sid_str_buf(connect_with_info->out.domain_sid,
     619             :                                         &buf),
     620             :                         nt_errstr(status));
     621           0 :                 talloc_free(tmp_ctx);
     622           0 :                 return status;
     623             :         }
     624             :         
     625             :         /* prepare samr_CreateUser2 */
     626         557 :         ZERO_STRUCTP(u_handle);
     627         557 :         cu.in.domain_handle  = &d_handle;
     628         557 :         cu.in.access_mask     = SEC_FLAG_MAXIMUM_ALLOWED;
     629         557 :         samr_account_name.string = r->in.account_name;
     630         557 :         cu.in.account_name    = &samr_account_name;
     631         557 :         cu.in.acct_flags      = r->in.acct_type;
     632         557 :         cu.out.user_handle    = u_handle;
     633         557 :         cu.out.rid            = &rid;
     634         557 :         cu.out.access_granted = &access_granted;
     635             : 
     636             :         /* do a samr_CreateUser2 to get an account handle, or an error */
     637         557 :         cu_status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu);
     638         557 :         if (NT_STATUS_IS_OK(cu_status) && !NT_STATUS_IS_OK(cu.out.result)) {
     639           0 :                 cu_status = cu.out.result;
     640             :         }
     641         557 :         status = cu_status;
     642         557 :         if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
     643             :                 /* prepare samr_LookupNames */
     644           0 :                 ln.in.domain_handle = &d_handle;
     645           0 :                 ln.in.num_names = 1;
     646           0 :                 ln.in.names = talloc_array(tmp_ctx, struct lsa_String, 1);
     647           0 :                 ln.out.rids = &rids;
     648           0 :                 ln.out.types = &types;
     649           0 :                 if (!ln.in.names) {
     650           0 :                         r->out.error_string = NULL;
     651           0 :                         talloc_free(tmp_ctx);
     652           0 :                         return NT_STATUS_NO_MEMORY;
     653             :                 }
     654           0 :                 ln.in.names[0].string = r->in.account_name;
     655             :                 
     656             :                 /* 5. do a samr_LookupNames to get the users rid */
     657           0 :                 status = dcerpc_samr_LookupNames_r(samr_pipe->binding_handle, tmp_ctx, &ln);
     658           0 :                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ln.out.result)) {
     659           0 :                         status = ln.out.result;
     660             :                 }
     661           0 :                 if (!NT_STATUS_IS_OK(status)) {
     662           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     663             :                                                 "samr_LookupNames for [%s] failed: %s",
     664             :                                                 r->in.account_name,
     665             :                                                 nt_errstr(status));
     666           0 :                         talloc_free(tmp_ctx);
     667           0 :                         return status;
     668             :                 }
     669             :                 
     670             :                 /* check if we got one RID for the user */
     671           0 :                 if (ln.out.rids->count != 1) {
     672           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     673             :                                                               "samr_LookupNames for [%s] returns %d RIDs",
     674           0 :                                                               r->in.account_name, ln.out.rids->count);
     675           0 :                         talloc_free(tmp_ctx);
     676           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     677             :                 }
     678             : 
     679           0 :                 if (ln.out.types->count != 1) {
     680           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     681             :                                                                 "samr_LookupNames for [%s] returns %d RID TYPEs",
     682           0 :                                                                 r->in.account_name, ln.out.types->count);
     683           0 :                         talloc_free(tmp_ctx);
     684           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     685             :                 }
     686             : 
     687             :                 /* prepare samr_OpenUser */
     688           0 :                 ZERO_STRUCTP(u_handle);
     689           0 :                 ou.in.domain_handle = &d_handle;
     690           0 :                 ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
     691           0 :                 ou.in.rid = ln.out.rids->ids[0];
     692           0 :                 rid = ou.in.rid;
     693           0 :                 ou.out.user_handle = u_handle;
     694             :                 
     695             :                 /* 6. do a samr_OpenUser to get a user handle */
     696           0 :                 status = dcerpc_samr_OpenUser_r(samr_pipe->binding_handle, tmp_ctx, &ou);
     697           0 :                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ou.out.result)) {
     698           0 :                         status = ou.out.result;
     699             :                 }
     700           0 :                 if (!NT_STATUS_IS_OK(status)) {
     701           0 :                         r->out.error_string = talloc_asprintf(mem_ctx,
     702             :                                                         "samr_OpenUser for [%s] failed: %s",
     703             :                                                         r->in.account_name,
     704             :                                                         nt_errstr(status));
     705           0 :                         talloc_free(tmp_ctx);
     706           0 :                         return status;
     707             :                 }
     708             : 
     709           0 :                 if (r->in.recreate_account) {
     710           0 :                         struct samr_DeleteUser d;
     711           0 :                         d.in.user_handle = u_handle;
     712           0 :                         d.out.user_handle = u_handle;
     713           0 :                         status = dcerpc_samr_DeleteUser_r(samr_pipe->binding_handle, mem_ctx, &d);
     714           0 :                         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(d.out.result)) {
     715           0 :                                 status = d.out.result;
     716             :                         }
     717           0 :                         if (!NT_STATUS_IS_OK(status)) {
     718           0 :                                 r->out.error_string = talloc_asprintf(mem_ctx,
     719             :                                                                       "samr_DeleteUser (for recreate) of [%s] failed: %s",
     720             :                                                                       r->in.account_name,
     721             :                                                                       nt_errstr(status));
     722           0 :                                 talloc_free(tmp_ctx);
     723           0 :                                 return status;
     724             :                         }
     725             : 
     726             :                         /* We want to recreate, so delete and another samr_CreateUser2 */
     727             :                         
     728             :                         /* &cu filled in above */
     729           0 :                         status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu);
     730           0 :                         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(cu.out.result)) {
     731           0 :                                 status = cu.out.result;
     732             :                         }
     733           0 :                         if (!NT_STATUS_IS_OK(status)) {
     734           0 :                                 r->out.error_string = talloc_asprintf(mem_ctx,
     735             :                                                                       "samr_CreateUser2 (recreate) for [%s] failed: %s",
     736             :                                                                       r->in.account_name, nt_errstr(status));
     737           0 :                                 talloc_free(tmp_ctx);
     738           0 :                                 return status;
     739             :                         }
     740             :                 }
     741         557 :         } else if (!NT_STATUS_IS_OK(status)) {
     742           0 :                 r->out.error_string = talloc_asprintf(mem_ctx,
     743             :                                                       "samr_CreateUser2 for [%s] failed: %s",
     744             :                                                       r->in.account_name, nt_errstr(status));
     745           0 :                 talloc_free(tmp_ctx);
     746           0 :                 return status;
     747             :         }
     748             : 
     749             :         /* prepare samr_QueryUserInfo (get flags) */
     750         557 :         qui.in.user_handle = u_handle;
     751         557 :         qui.in.level = 16;
     752         557 :         qui.out.info = &uinfo;
     753             :         
     754         557 :         status = dcerpc_samr_QueryUserInfo_r(samr_pipe->binding_handle, tmp_ctx, &qui);
     755         557 :         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(qui.out.result)) {
     756           0 :                 status = qui.out.result;
     757             :         }
     758         557 :         if (!NT_STATUS_IS_OK(status)) {
     759           0 :                 r->out.error_string = talloc_asprintf(mem_ctx,
     760             :                                                 "samr_QueryUserInfo for [%s] failed: %s",
     761             :                                                 r->in.account_name,
     762             :                                                 nt_errstr(status));
     763           0 :                 talloc_free(tmp_ctx);
     764           0 :                 return status;
     765             :         }
     766             :         
     767         557 :         if (!uinfo) {
     768           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     769           0 :                 r->out.error_string
     770           0 :                         = talloc_asprintf(mem_ctx,
     771             :                                           "samr_QueryUserInfo failed to return qui.out.info for [%s]: %s",
     772             :                                           r->in.account_name, nt_errstr(status));
     773           0 :                 talloc_free(tmp_ctx);
     774           0 :                 return status;
     775             :         }
     776             : 
     777         557 :         old_acct_flags = (uinfo->info16.acct_flags & (ACB_WSTRUST | ACB_SVRTRUST | ACB_DOMTRUST));
     778             :         /* Possibly bail if the account is of the wrong type */
     779         557 :         if (old_acct_flags
     780         557 :             != r->in.acct_type) {
     781           0 :                 const char *old_account_type, *new_account_type;
     782           0 :                 switch (old_acct_flags) {
     783           0 :                 case ACB_WSTRUST:
     784           0 :                         old_account_type = "domain member (member)";
     785           0 :                         break;
     786           0 :                 case ACB_SVRTRUST:
     787           0 :                         old_account_type = "domain controller (bdc)";
     788           0 :                         break;
     789           0 :                 case ACB_DOMTRUST:
     790           0 :                         old_account_type = "trusted domain";
     791           0 :                         break;
     792           0 :                 default:
     793           0 :                         return NT_STATUS_INVALID_PARAMETER;
     794             :                 }
     795           0 :                 switch (r->in.acct_type) {
     796           0 :                 case ACB_WSTRUST:
     797           0 :                         new_account_type = "domain member (member)";
     798           0 :                         break;
     799           0 :                 case ACB_SVRTRUST:
     800           0 :                         new_account_type = "domain controller (bdc)";
     801           0 :                         break;
     802           0 :                 case ACB_DOMTRUST:
     803           0 :                         new_account_type = "trusted domain";
     804           0 :                         break;
     805           0 :                 default:
     806           0 :                         return NT_STATUS_INVALID_PARAMETER;
     807             :                 }
     808             : 
     809           0 :                 if (!NT_STATUS_EQUAL(cu_status, NT_STATUS_USER_EXISTS)) {
     810             :                         /* We created a new user, but they didn't come out the right type?!? */
     811           0 :                         r->out.error_string
     812           0 :                                 = talloc_asprintf(mem_ctx,
     813             :                                                   "We asked to create a new machine account (%s) of type %s, "
     814             :                                                   "but we got an account of type %s.  This is unexpected.  "
     815             :                                                   "Perhaps delete the account and try again.",
     816             :                                                   r->in.account_name, new_account_type, old_account_type);
     817           0 :                         talloc_free(tmp_ctx);
     818           0 :                         return NT_STATUS_INVALID_PARAMETER;
     819             :                 } else {
     820             :                         /* The account is of the wrong type, so bail */
     821             : 
     822             :                         /* TODO: We should allow a --force option to override, and redo this from the top setting r.in.recreate_account */
     823           0 :                         r->out.error_string
     824           0 :                                 = talloc_asprintf(mem_ctx,
     825             :                                                   "The machine account (%s) already exists in the domain %s, "
     826             :                                                   "but is a %s.  You asked to join as a %s.  Please delete "
     827             :                                                   "the account and try again.",
     828             :                                                   r->in.account_name, connect_with_info->out.domain_name, old_account_type, new_account_type);
     829           0 :                         talloc_free(tmp_ctx);
     830           0 :                         return NT_STATUS_USER_EXISTS;
     831             :                 }
     832             :         } else {
     833         557 :                 acct_flags = uinfo->info16.acct_flags;
     834             :         }
     835             :         
     836         557 :         acct_flags = (acct_flags & ~(ACB_DISABLED|ACB_PWNOTREQ));
     837             : 
     838             :         /* Find out what password policy this user has */
     839         557 :         pwp.in.user_handle = u_handle;
     840         557 :         pwp.out.info = &info;
     841             : 
     842         557 :         status = dcerpc_samr_GetUserPwInfo_r(samr_pipe->binding_handle, tmp_ctx, &pwp);
     843         557 :         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(pwp.out.result)) {
     844           0 :                 status = pwp.out.result;
     845             :         }
     846         557 :         if (NT_STATUS_IS_OK(status)) {
     847         557 :                 policy_min_pw_len = pwp.out.info->min_password_length;
     848             :         }
     849             : 
     850         557 :         if (r->in.account_pass != NULL) {
     851          11 :                 password_str = talloc_strdup(tmp_ctx, r->in.account_pass);
     852             :         } else {
     853             :                 /* Grab a password of that minimum length */
     854         546 :                 password_str = generate_random_password(tmp_ctx,
     855         546 :                                         MAX(8, policy_min_pw_len), 255);
     856             :         }
     857         557 :         if (!password_str) {
     858           0 :                 r->out.error_string = NULL;
     859           0 :                 talloc_free(tmp_ctx);
     860           0 :                 return NT_STATUS_NO_MEMORY;
     861             :         }
     862             : 
     863             :         /* set full_name and reset flags */
     864         557 :         ZERO_STRUCT(u_info21);
     865         557 :         u_info21.full_name.string       = r->in.account_name;
     866         557 :         u_info21.acct_flags             = acct_flags;
     867         557 :         u_info21.fields_present         = SAMR_FIELD_FULL_NAME | SAMR_FIELD_ACCT_FLAGS;
     868             : 
     869         557 :         r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
     870         557 :         r2.samr_handle.in.account_name  = r->in.account_name;
     871         557 :         r2.samr_handle.in.newpassword   = password_str;
     872         557 :         r2.samr_handle.in.user_handle   = u_handle;
     873         557 :         r2.samr_handle.in.dcerpc_pipe   = samr_pipe;
     874         557 :         r2.samr_handle.in.info21        = &u_info21;
     875             : 
     876         557 :         status = libnet_SetPassword(ctx, tmp_ctx, &r2);     
     877         557 :         if (!NT_STATUS_IS_OK(status)) {
     878           0 :                 r->out.error_string = talloc_steal(mem_ctx, r2.samr_handle.out.error_string);
     879           0 :                 talloc_free(tmp_ctx);
     880           0 :                 return status;
     881             :         }
     882             : 
     883         557 :         account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid);
     884         557 :         if (!account_sid) {
     885           0 :                 r->out.error_string = NULL;
     886           0 :                 talloc_free(tmp_ctx);
     887           0 :                 return NT_STATUS_NO_MEMORY;
     888             :         }
     889             : 
     890             :         /* Finish out by pushing various bits of status data out for the caller to use */
     891         557 :         r->out.join_password = password_str;
     892         557 :         talloc_steal(mem_ctx, r->out.join_password);
     893             : 
     894         557 :         r->out.domain_sid = connect_with_info->out.domain_sid;
     895         557 :         talloc_steal(mem_ctx, r->out.domain_sid);
     896             : 
     897         557 :         r->out.account_sid = account_sid;
     898         557 :         talloc_steal(mem_ctx, r->out.account_sid);
     899             : 
     900         557 :         r->out.domain_name = connect_with_info->out.domain_name;
     901         557 :         talloc_steal(mem_ctx, r->out.domain_name);
     902         557 :         r->out.realm = connect_with_info->out.realm;
     903         557 :         talloc_steal(mem_ctx, r->out.realm);
     904         557 :         r->out.samr_pipe = samr_pipe;
     905         557 :         talloc_reparent(tmp_ctx, mem_ctx, samr_pipe);
     906         557 :         r->out.samr_binding = samr_pipe->binding;
     907         557 :         r->out.user_handle = u_handle;
     908         557 :         talloc_steal(mem_ctx, u_handle);
     909         557 :         r->out.error_string = r2.samr_handle.out.error_string;
     910         557 :         talloc_steal(mem_ctx, r2.samr_handle.out.error_string);
     911         557 :         r->out.kvno = 0;
     912         557 :         r->out.server_dn_str = NULL;
     913         557 :         talloc_free(tmp_ctx); 
     914             : 
     915             :         /* Now, if it was AD, then we want to start looking changing a
     916             :          * few more things.  Otherwise, we are done. */
     917         557 :         if (r->out.realm) {
     918         507 :                 status = libnet_JoinADSDomain(ctx, r);
     919         507 :                 return status;
     920             :         }
     921             : 
     922          50 :         return status;
     923             : }
     924             : 
     925          13 : NTSTATUS libnet_Join_member(struct libnet_context *ctx,
     926             :                             TALLOC_CTX *mem_ctx,
     927             :                             struct libnet_Join_member *r)
     928             : {
     929           7 :         NTSTATUS status;
     930           7 :         TALLOC_CTX *tmp_mem;
     931           7 :         struct libnet_JoinDomain *r2;
     932           7 :         struct provision_store_self_join_settings *set_secrets;
     933          13 :         uint32_t acct_type = 0;
     934           7 :         const char *account_name;
     935           7 :         const char *netbios_name;
     936          13 :         const char *error_string = NULL;
     937             : 
     938          13 :         r->out.error_string = NULL;
     939             : 
     940          13 :         tmp_mem = talloc_new(mem_ctx);
     941          13 :         if (!tmp_mem) {
     942           0 :                 return NT_STATUS_NO_MEMORY;
     943             :         }
     944             : 
     945          13 :         r2 = talloc_zero(tmp_mem, struct libnet_JoinDomain);
     946          13 :         if (!r2) {
     947           0 :                 status = NT_STATUS_NO_MEMORY;
     948           0 :                 goto out;
     949             :         }
     950             : 
     951          13 :         acct_type = ACB_WSTRUST;
     952             : 
     953          13 :         if (r->in.netbios_name != NULL) {
     954           6 :                 netbios_name = r->in.netbios_name;
     955             :         } else {
     956           0 :                 netbios_name = talloc_strdup(tmp_mem, lpcfg_netbios_name(ctx->lp_ctx));
     957           0 :                 if (!netbios_name) {
     958           0 :                         status = NT_STATUS_NO_MEMORY;
     959           0 :                         goto out;
     960             :                 }
     961             :         }
     962             : 
     963          13 :         account_name = talloc_asprintf(tmp_mem, "%s$", netbios_name);
     964          13 :         if (!account_name) {
     965           0 :                 status = NT_STATUS_NO_MEMORY;
     966           0 :                 goto out;
     967             :         }
     968             : 
     969             :         /*
     970             :          * join the domain
     971             :          */
     972          13 :         r2->in.domain_name   = r->in.domain_name;
     973          13 :         r2->in.account_name  = account_name;
     974          13 :         r2->in.netbios_name  = netbios_name;
     975          13 :         r2->in.level         = LIBNET_JOINDOMAIN_AUTOMATIC;
     976          13 :         r2->in.acct_type     = acct_type;
     977          13 :         r2->in.recreate_account = false;
     978          13 :         r2->in.account_pass  = r->in.account_pass;
     979          13 :         status = libnet_JoinDomain(ctx, r2, r2);
     980          13 :         if (!NT_STATUS_IS_OK(status)) {
     981           2 :                 r->out.error_string = talloc_steal(mem_ctx, r2->out.error_string);
     982           2 :                 goto out;
     983             :         }
     984             : 
     985          11 :         set_secrets = talloc_zero(tmp_mem,
     986             :                                   struct provision_store_self_join_settings);
     987          11 :         if (!set_secrets) {
     988           0 :                 status = NT_STATUS_NO_MEMORY;
     989           0 :                 goto out;
     990             :         }
     991             : 
     992          11 :         set_secrets->domain_name = r2->out.domain_name;
     993          11 :         set_secrets->realm = r2->out.realm;
     994          11 :         set_secrets->netbios_name = netbios_name;
     995          11 :         set_secrets->secure_channel_type = SEC_CHAN_WKSTA;
     996          11 :         set_secrets->machine_password = r2->out.join_password;
     997          11 :         set_secrets->key_version_number = r2->out.kvno;
     998          11 :         set_secrets->domain_sid = r2->out.domain_sid;
     999             : 
    1000          11 :         status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
    1001          11 :         if (!NT_STATUS_IS_OK(status)) {
    1002           0 :                 if (error_string) {
    1003           0 :                         r->out.error_string = talloc_steal(mem_ctx, error_string);
    1004             :                 } else {
    1005           0 :                         r->out.error_string
    1006           0 :                                 = talloc_asprintf(mem_ctx,
    1007             :                                                   "provision_store_self_join failed with %s",
    1008             :                                                   nt_errstr(status));
    1009             :                 }
    1010           0 :                 goto out;
    1011             :         }
    1012             : 
    1013             :         /* move all out parameter to the callers TALLOC_CTX */
    1014          11 :         r->out.join_password = talloc_move(mem_ctx, &r2->out.join_password);
    1015          11 :         r->out.domain_sid    = talloc_move(mem_ctx, &r2->out.domain_sid);
    1016          11 :         r->out.domain_name      = talloc_move(mem_ctx, &r2->out.domain_name);
    1017          11 :         status = NT_STATUS_OK;
    1018          13 : out:
    1019          13 :         talloc_free(tmp_mem);
    1020          13 :         return status;
    1021             : }
    1022             : 

Generated by: LCOV version 1.14