s4-winbind: use finddcs_cldap() in winbind
[kamenim/samba.git] / source4 / winbind / wb_init_domain.c
index 0099d7a27c1aa69a861009db3911d83d3775e51c..50a6af05fd6e48c0580fca659ec0b964a19d7f8a 100644 (file)
@@ -8,7 +8,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "libcli/composite/composite.h"
-#include "libcli/smb_composite/smb_composite.h"
 #include "winbind/wb_server.h"
-#include "winbind/wb_async_helpers.h"
-#include "winbind/wb_helper.h"
 #include "smbd/service_task.h"
 #include "librpc/gen_ndr/ndr_netlogon.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
 #include "librpc/gen_ndr/ndr_samr_c.h"
 #include "libcli/libcli.h"
 
-#include "libcli/auth/credentials.h"
 #include "libcli/security/security.h"
 
-#include "libcli/ldap/ldap_client.h"
 
 #include "auth/credentials/credentials.h"
+#include "param/param.h"
 
 /*
  * Initialize a domain:
@@ -70,17 +65,17 @@ struct init_domain_state {
        struct lsa_ObjectAttribute objectattr;
        struct lsa_OpenPolicy2 lsa_openpolicy;
        struct lsa_QueryInfoPolicy queryinfo;
+       union lsa_PolicyInformation *info;
 };
 
 static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
 static void init_domain_recv_lsa_pipe(struct composite_context *ctx);
-static void init_domain_recv_lsa_policy(struct rpc_request *req);
-static void init_domain_recv_queryinfo(struct rpc_request *req);
-static void init_domain_recv_ldapconn(struct composite_context *ctx);
+static void init_domain_recv_lsa_policy(struct tevent_req *subreq);
+static void init_domain_recv_queryinfo(struct tevent_req *subreq);
 static void init_domain_recv_samr(struct composite_context *ctx);
 
 static struct dcerpc_binding *init_domain_binding(struct init_domain_state *state, 
-                                                 const struct dcerpc_interface_table *table) 
+                                                 const struct ndr_interface_table *table) 
 {
        struct dcerpc_binding *binding;
        NTSTATUS status;
@@ -101,7 +96,8 @@ static struct dcerpc_binding *init_domain_binding(struct init_domain_state *stat
        binding->host = state->domain->dc_address;
 
        /* This shouldn't make a network call, as the mappings for named pipes are well known */
-       status = dcerpc_epm_map_binding(binding, binding, table, state->service->task->event_ctx);
+       status = dcerpc_epm_map_binding(binding, binding, table, state->service->task->event_ctx,
+                                       state->service->task->lp_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                return NULL;
        }
@@ -132,43 +128,36 @@ struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
        state->domain->info = talloc_reference(state->domain, dom_info);
        if (state->domain->info == NULL) goto failed;
 
-       /* Caller should check, but to be safe: */
-       if (dom_info->num_dcs < 1) {
-               goto failed;
-       }
-       
-       /* For now, we just pick the first.  The next step will be to
-        * walk the entire list.  Also need to fix finddcs() to return
-        * the entire list */
-       state->domain->dc_name = dom_info->dcs[0].name;
-       state->domain->dc_address = dom_info->dcs[0].address;
+       state->domain->dc_name = dom_info->dc->name;
+       state->domain->dc_address = dom_info->dc->address;
 
-       /* Create a credentials structure */
-       state->domain->schannel_creds = cli_credentials_init(state->domain);
-       if (state->domain->schannel_creds == NULL) goto failed;
+       state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx, 
+                                                       service->task->lp_ctx);
 
-       cli_credentials_set_event_context(state->domain->schannel_creds, service->task->event_ctx);
+       /* Create a credentials structure */
+       state->domain->libnet_ctx->cred = cli_credentials_init(state->domain);
+       if (state->domain->libnet_ctx->cred == NULL) goto failed;
 
-       cli_credentials_set_conf(state->domain->schannel_creds);
+       cli_credentials_set_conf(state->domain->libnet_ctx->cred, service->task->lp_ctx);
 
        /* Connect the machine account to the credentials */
        state->ctx->status =
-               cli_credentials_set_machine_account(state->domain->
-                                                   schannel_creds);
+               cli_credentials_set_machine_account(state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx);
        if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
 
-       state->domain->netlogon_binding = init_domain_binding(state, &dcerpc_table_netlogon);
+       state->domain->netlogon_binding = init_domain_binding(state, &ndr_table_netlogon);
 
        state->domain->netlogon_pipe = NULL;
 
-       if ((!cli_credentials_is_anonymous(state->domain->schannel_creds)) &&
-           ((lp_server_role() == ROLE_DOMAIN_MEMBER) &&
-            (dom_sid_equal(state->domain->info->sid,
-                           state->service->primary_sid)))) {
+       if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) &&
+           ((lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) ||
+            (lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) &&
+           (dom_sid_equal(state->domain->info->sid,
+                          state->service->primary_sid))) {
                state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL;
 
                /* For debugging, it can be a real pain if all the traffic is encrypted */
-               if (lp_winbind_sealed_pipes()) {
+               if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) {
                        state->domain->netlogon_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
                } else {
                        state->domain->netlogon_binding->flags |= (DCERPC_SIGN);
@@ -178,9 +167,10 @@ struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
        /* No encryption on anonymous pipes */
 
        ctx = dcerpc_pipe_connect_b_send(state, state->domain->netlogon_binding, 
-                                        &dcerpc_table_netlogon,
-                                        state->domain->schannel_creds,
-                                        service->task->event_ctx);
+                                        &ndr_table_netlogon,
+                                        state->domain->libnet_ctx->cred,
+                                        service->task->event_ctx,
+                                        service->task->lp_ctx);
        
        if (composite_nomem(ctx, state->ctx)) {
                goto failed;
@@ -202,38 +192,43 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
                talloc_get_type(ctx->async.private_data,
                                struct init_domain_state);
 
-       state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state, 
+       state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain
                                                   &state->domain->netlogon_pipe);
        
        if (!composite_is_ok(state->ctx)) {
-               talloc_free(state->domain->netlogon_binding);
                return;
        }
-       talloc_steal(state->domain->netlogon_pipe, state->domain->netlogon_binding);
+       talloc_reparent(state, state->domain->netlogon_pipe, state->domain->netlogon_binding);
 
-       state->domain->lsa_binding = init_domain_binding(state, &dcerpc_table_lsarpc);
+       state->domain->lsa_binding = init_domain_binding(state, &ndr_table_lsarpc);
 
        /* For debugging, it can be a real pain if all the traffic is encrypted */
-       if (lp_winbind_sealed_pipes()) {
+       if (lpcfg_winbind_sealed_pipes(state->service->task->lp_ctx)) {
                state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
        } else {
                state->domain->lsa_binding->flags |= (DCERPC_SIGN);
        }
 
-       state->domain->lsa_pipe = NULL;
+       state->domain->libnet_ctx->lsa.pipe = NULL;
 
        /* this will make the secondary connection on the same IPC$ share, 
           secured with SPNEGO or NTLMSSP */
-       ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe,
-                                              state->domain->lsa_binding);
+       ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
+                                                   state->domain->lsa_binding,
+                                                   &ndr_table_lsarpc,
+                                                   state->domain->libnet_ctx->cred,
+                                                   state->domain->libnet_ctx->lp_ctx
+               );
        composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
 }
 
 static bool retry_with_schannel(struct init_domain_state *state, 
                                struct dcerpc_binding *binding,
+                               const struct ndr_interface_table *table,
                                void (*continuation)(struct composite_context *))
 {
        struct composite_context *ctx;
+       state->ctx->status = NT_STATUS_OK;
        if (state->domain->netlogon_binding->flags & DCERPC_SCHANNEL 
            && !(binding->flags & DCERPC_SCHANNEL)) {
                /* Opening a policy handle failed, perhaps it was
@@ -245,8 +240,11 @@ static bool retry_with_schannel(struct init_domain_state *state,
 
                /* Try again, likewise on the same IPC$ share, 
                   secured with SCHANNEL */
-               ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe,
-                                                      binding);
+               ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
+                                                           binding,
+                                                           table, 
+                                                           state->domain->libnet_ctx->cred,
+                                                           state->domain->libnet_ctx->lp_ctx);
                composite_continue(state->ctx, ctx, continuation, state);               
                return true;
        } else {
@@ -258,54 +256,59 @@ static bool retry_with_schannel(struct init_domain_state *state,
  */    
 static void init_domain_recv_lsa_pipe(struct composite_context *ctx)
 {
-       struct rpc_request *req;
        struct init_domain_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct init_domain_state);
+       struct tevent_req *subreq;
 
-       state->ctx->status = dcerpc_secondary_connection_recv(ctx, 
-                                                             &state->domain->lsa_pipe);
+       state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state->domain,
+                                                                  &state->domain->libnet_ctx->lsa.pipe);
        if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) {
                if (retry_with_schannel(state, state->domain->lsa_binding, 
+                                       &ndr_table_lsarpc,
                                        init_domain_recv_lsa_pipe)) {
                        return;
                }
        }
        if (!composite_is_ok(state->ctx)) return;
 
-       talloc_steal(state->domain, state->domain->lsa_pipe);
-       talloc_steal(state->domain->lsa_pipe, state->domain->lsa_binding);
-
-       state->domain->lsa_policy_handle = talloc(state, struct policy_handle);
-       if (composite_nomem(state->domain->lsa_policy_handle, state->ctx)) return;
+       talloc_steal(state->domain->libnet_ctx, state->domain->libnet_ctx->lsa.pipe);
+       talloc_reparent(state, state->domain->libnet_ctx->lsa.pipe, state->domain->lsa_binding);
+       state->domain->libnet_ctx->lsa.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       state->domain->libnet_ctx->lsa.name = state->domain->info->name;
 
+       ZERO_STRUCT(state->domain->libnet_ctx->lsa.handle);
        state->lsa_openpolicy.in.system_name =
                talloc_asprintf(state, "\\\\%s",
-                               dcerpc_server_name(state->domain->lsa_pipe));
+                               dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe));
        ZERO_STRUCT(state->objectattr);
        state->lsa_openpolicy.in.attr = &state->objectattr;
        state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       state->lsa_openpolicy.out.handle = state->domain->lsa_policy_handle;
-
-       req = dcerpc_lsa_OpenPolicy2_send(state->domain->lsa_pipe, state,
-                                         &state->lsa_openpolicy);
-
-       composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state);
+       state->lsa_openpolicy.out.handle = &state->domain->libnet_ctx->lsa.handle;
+
+       subreq = dcerpc_lsa_OpenPolicy2_r_send(state,
+                                              state->ctx->event_ctx,
+                                              state->domain->libnet_ctx->lsa.pipe->binding_handle,
+                                              &state->lsa_openpolicy);
+       if (composite_nomem(subreq, state->ctx)) return;
+       tevent_req_set_callback(subreq, init_domain_recv_lsa_policy, state);
 }
 
 /* Receive a policy handle (or not, and retry the authentication) and
  * obtain some basic information about the domain */
 
-static void init_domain_recv_lsa_policy(struct rpc_request *req)
+static void init_domain_recv_lsa_policy(struct tevent_req *subreq)
 {
        struct init_domain_state *state =
-               talloc_get_type(req->async.private_data,
-                               struct init_domain_state);
+               tevent_req_callback_data(subreq,
+               struct init_domain_state);
 
-       state->ctx->status = dcerpc_ndr_request_recv(req);
-       if (!(NT_STATUS_IS_OK(state->ctx->status)
-             && NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) {
+       state->ctx->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, state);
+       TALLOC_FREE(subreq);
+       if ((!NT_STATUS_IS_OK(state->ctx->status)
+             || !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) {
                if (retry_with_schannel(state, state->domain->lsa_binding, 
+                                       &ndr_table_lsarpc,
                                        init_domain_recv_lsa_pipe)) {
                        return;
                }
@@ -314,33 +317,41 @@ static void init_domain_recv_lsa_policy(struct rpc_request *req)
        state->ctx->status = state->lsa_openpolicy.out.result;
        if (!composite_is_ok(state->ctx)) return;
 
-       state->queryinfo.in.handle = state->domain->lsa_policy_handle;
-       state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
+       state->info = talloc_zero(state->ctx, union lsa_PolicyInformation);
+       if (composite_nomem(state->info, state->ctx)) return;
 
-       req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->lsa_pipe, state,
-                                             &state->queryinfo);
-       composite_continue_rpc(state->ctx, req,
-                              init_domain_recv_queryinfo, state);
+       state->queryinfo.in.handle = &state->domain->libnet_ctx->lsa.handle;
+       state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
+       state->queryinfo.out.info = &state->info;
+
+       subreq = dcerpc_lsa_QueryInfoPolicy_r_send(state,
+                                                  state->ctx->event_ctx,
+                                                  state->domain->libnet_ctx->lsa.pipe->binding_handle,
+                                                  &state->queryinfo);
+       if (composite_nomem(subreq, state->ctx)) return;
+       tevent_req_set_callback(subreq, init_domain_recv_queryinfo, state);
 }
 
-static void init_domain_recv_queryinfo(struct rpc_request *req)
+static void init_domain_recv_queryinfo(struct tevent_req *subreq)
 {
        struct init_domain_state *state =
-               talloc_get_type(req->async.private_data, struct init_domain_state);
+               tevent_req_callback_data(subreq,
+               struct init_domain_state);
        struct lsa_DomainInfo *dominfo;
        struct composite_context *ctx;
 
-       state->ctx->status = dcerpc_ndr_request_recv(req);
+       state->ctx->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, state);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(state->ctx)) return;
        state->ctx->status = state->queryinfo.out.result;
        if (!composite_is_ok(state->ctx)) return;
 
-       dominfo = &state->queryinfo.out.info->account_domain;
+       dominfo = &(*state->queryinfo.out.info)->account_domain;
 
        if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
                DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
                          state->domain->info->name,
-                         dcerpc_server_name(state->domain->lsa_pipe),
+                         dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
                          dominfo->name.string));
                composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
                return;
@@ -349,19 +360,19 @@ static void init_domain_recv_queryinfo(struct rpc_request *req)
        if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
                DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
                          dom_sid_string(state, state->domain->info->sid),
-                         dcerpc_server_name(state->domain->lsa_pipe),
+                         dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
                          dom_sid_string(state, dominfo->sid)));
                composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
                return;
        }
 
-       state->domain->samr_binding = init_domain_binding(state, &dcerpc_table_samr);
+       state->domain->samr_binding = init_domain_binding(state, &ndr_table_samr);
 
        /* We want to use the same flags as the LSA pipe did (so, if
         * it needed schannel, then we need that here too) */
        state->domain->samr_binding->flags = state->domain->lsa_binding->flags;
 
-       state->domain->samr_pipe = NULL;
+       state->domain->libnet_ctx->samr.pipe = NULL;
 
        ctx = wb_connect_samr_send(state, state->domain);
        composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
@@ -371,49 +382,23 @@ static void init_domain_recv_queryinfo(struct rpc_request *req)
  * open an LDAP connection */
 static void init_domain_recv_samr(struct composite_context *ctx)
 {
-       const char *ldap_url;
        struct init_domain_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct init_domain_state);
 
        state->ctx->status = wb_connect_samr_recv(
                ctx, state->domain,
-               &state->domain->samr_pipe,
-               &state->domain->samr_handle, 
-               &state->domain->domain_handle);
+               &state->domain->libnet_ctx->samr.pipe,
+               &state->domain->libnet_ctx->samr.connect_handle,
+               &state->domain->libnet_ctx->samr.handle);
        if (!composite_is_ok(state->ctx)) return;
 
-       talloc_steal(state->domain->samr_pipe, state->domain->samr_binding);
-
-       state->domain->ldap_conn =
-               ldap4_new_connection(state->domain, state->ctx->event_ctx);
-       composite_nomem(state->domain->ldap_conn, state->ctx);
-
-       ldap_url = talloc_asprintf(state, "ldap://%s/",
-                                  state->domain->dc_address);
-       composite_nomem(ldap_url, state->ctx);
-
-       ctx = ldap_connect_send(state->domain->ldap_conn, ldap_url);
-       composite_continue(state->ctx, ctx, init_domain_recv_ldapconn, state);
-}
-
-static void init_domain_recv_ldapconn(struct composite_context *ctx)
-{
-       struct init_domain_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_domain_state);
-
-       state->ctx->status = ldap_connect_recv(ctx);
-       if (NT_STATUS_IS_OK(state->ctx->status)) {
-               state->domain->ldap_conn->host =
-                       talloc_strdup(state->domain->ldap_conn,
-                                     state->domain->dc_name);
-               state->ctx->status =
-                       ldap_bind_sasl(state->domain->ldap_conn,
-                                      state->domain->schannel_creds);
-               DEBUG(0, ("ldap_bind returned %s\n",
-                         nt_errstr(state->ctx->status)));
-       }
+       talloc_reparent(state, state->domain->libnet_ctx->samr.pipe, state->domain->samr_binding);
+       state->domain->libnet_ctx->samr.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       state->domain->libnet_ctx->samr.name = state->domain->info->name;
+       state->domain->libnet_ctx->samr.sid = dom_sid_dup(
+                                               state->domain->libnet_ctx,
+                                               state->domain->info->sid);
 
        composite_done(state->ctx);
 }