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

Generated by: LCOV version 1.14