lib/param: Create a seperate server role for "active directory domain controller"
[amitay/samba.git] / source4 / winbind / wb_init_domain.c
index 5953474c52fdf680630685a8363b9ffbd01317d8..45a4b98f31166e83b3919bf41c723059f21c1011 100644 (file)
 
 #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"
@@ -75,31 +70,42 @@ struct init_domain_state {
 
 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_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 ndr_interface_table *table) 
 {
        struct dcerpc_binding *binding;
+       char *s;
        NTSTATUS status;
 
        /* Make a binding string */
-       {
-               char *s = talloc_asprintf(state, "ncacn_np:%s", state->domain->dc_name);
+       if ((lpcfg_server_role(state->service->task->lp_ctx) != ROLE_DOMAIN_MEMBER) &&
+           dom_sid_equal(state->domain->info->sid, state->service->primary_sid) &&
+           state->service->sec_channel_type != SEC_CHAN_RODC) {
+               s = talloc_asprintf(state, "ncalrpc:%s", state->domain->dc_name);
                if (s == NULL) return NULL;
-               status = dcerpc_parse_binding(state, s, &binding);
-               talloc_free(s);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return NULL;
-               }
+       } else {
+               s = talloc_asprintf(state, "ncacn_np:%s", state->domain->dc_name);
+               if (s == NULL) return NULL;
+
+       }
+       status = dcerpc_parse_binding(state, s, &binding);
+       talloc_free(s);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NULL;
        }
 
        /* Alter binding to contain hostname, but also address (so we don't look it up twice) */
        binding->target_hostname = state->domain->dc_name;
        binding->host = state->domain->dc_address;
 
+       if (binding->transport == NCALRPC) {
+               return binding;
+       }
+
        /* 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,
                                        state->service->task->lp_ctx);
@@ -133,16 +139,8 @@ 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;
 
        state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx, 
                                                        service->task->lp_ctx);
@@ -163,14 +161,14 @@ struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
        state->domain->netlogon_pipe = NULL;
 
        if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) &&
-           ((lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) ||
-            (lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) &&
+           ((lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) ||
+            (lpcfg_server_role(service->task->lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC)) &&
            (dom_sid_equal(state->domain->info->sid,
                           state->service->primary_sid))) {
-               state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL;
+               state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO;
 
                /* For debugging, it can be a real pain if all the traffic is encrypted */
-               if (lp_winbind_sealed_pipes(service->task->lp_ctx)) {
+               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);
@@ -211,12 +209,12 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
        if (!composite_is_ok(state->ctx)) {
                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, &ndr_table_lsarpc);
 
        /* For debugging, it can be a real pain if all the traffic is encrypted */
-       if (lp_winbind_sealed_pipes(state->service->task->lp_ctx)) {
+       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);
@@ -249,7 +247,7 @@ static bool retry_with_schannel(struct init_domain_state *state,
                 * NTLMSSP binds */
 
                /* Try again with schannel */
-               binding->flags |= DCERPC_SCHANNEL;
+               binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO;
 
                /* Try again, likewise on the same IPC$ share, 
                   secured with SCHANNEL */
@@ -269,10 +267,10 @@ 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_auth_connection_recv(ctx, state->domain,
                                                                   &state->domain->libnet_ctx->lsa.pipe);
@@ -286,7 +284,7 @@ static void init_domain_recv_lsa_pipe(struct composite_context *ctx)
        if (!composite_is_ok(state->ctx)) return;
 
        talloc_steal(state->domain->libnet_ctx, state->domain->libnet_ctx->lsa.pipe);
-       talloc_steal(state->domain->libnet_ctx->lsa.pipe, state->domain->lsa_binding);
+       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;
 
@@ -299,22 +297,25 @@ static void init_domain_recv_lsa_pipe(struct composite_context *ctx)
        state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        state->lsa_openpolicy.out.handle = &state->domain->libnet_ctx->lsa.handle;
 
-       req = dcerpc_lsa_OpenPolicy2_send(state->domain->libnet_ctx->lsa.pipe, state,
-                                         &state->lsa_openpolicy);
-
-       composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state);
+       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);
+       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, 
@@ -334,20 +335,24 @@ static void init_domain_recv_lsa_policy(struct rpc_request *req)
        state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
        state->queryinfo.out.info = &state->info;
 
-       req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->libnet_ctx->lsa.pipe, state,
-                                             &state->queryinfo);
-       composite_continue_rpc(state->ctx, req,
-                              init_domain_recv_queryinfo, state);
+       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;
@@ -399,10 +404,12 @@ static void init_domain_recv_samr(struct composite_context *ctx)
                &state->domain->libnet_ctx->samr.handle);
        if (!composite_is_ok(state->ctx)) return;
 
-       talloc_steal(state->domain->libnet_ctx->samr.pipe, state->domain->samr_binding);
+       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 = state->domain->info->sid;
+       state->domain->libnet_ctx->samr.sid = dom_sid_dup(
+                                               state->domain->libnet_ctx,
+                                               state->domain->info->sid);
 
        composite_done(state->ctx);
 }