r23133: I felt pity on Kai, as he starts work on winbind in Samba4, so I
authorAndrew Bartlett <abartlet@samba.org>
Fri, 25 May 2007 08:04:39 +0000 (08:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:52:53 +0000 (14:52 -0500)
decided to clean it up a little.

We now use SPNEGO for authentication if possible, and common routines
shared with the rest of the librpc codebase.  Rather than make a
connection to IPC$, then connect the pipes to it, we instead have the
lsa and samr pipes as 'secondary connections'.

Andrew Bartlett
(This used to be commit 86654056b22245a57396544d572de6401069b9e5)

source4/winbind/wb_cmd_list_trustdom.c
source4/winbind/wb_cmd_lookupname.c
source4/winbind/wb_cmd_lookupsid.c
source4/winbind/wb_connect_lsa.c
source4/winbind/wb_connect_sam.c
source4/winbind/wb_init_domain.c
source4/winbind/wb_server.h

index c39fe499a7cb24ebc5041e741348805524aba68d..e45db6f96a9ba7f19419d87cebc0a60c715f2660 100644 (file)
@@ -85,8 +85,7 @@ static void cmd_list_trustdoms_recv_domain(struct composite_context *ctx)
        tree = dcerpc_smb_tree(domain->lsa_pipe->conn);
        if (composite_nomem(tree, state->ctx)) return;
 
-       ctx = wb_init_lsa_send(state, tree, domain->lsa_auth_type,
-                              domain->schannel_creds);
+       ctx = wb_init_lsa_send(state, domain);
        composite_continue(state->ctx, ctx, cmd_list_trustdoms_recv_lsa,
                           state);
 }
index 9b9b3d75740dd5d0554cdf9bf30a09c874e80046..ef3084bf0165199ecf12ad7c5778349114c34fec 100644 (file)
@@ -78,7 +78,7 @@ static void lookupname_recv_domain(struct composite_context *ctx)
        if (!composite_is_ok(state->ctx)) return;
 
        ctx = wb_lsa_lookupnames_send(state, domain->lsa_pipe,
-                                     domain->lsa_policy, 1, &state->name);
+                                     domain->lsa_policy_handle, 1, &state->name);
        composite_continue(state->ctx, ctx, lookupname_recv_sids, state);
 }
 
index 5e17c265e3aefd482faddf9c73ce6b5e084118a2..833be542a5b78760c8d05393988d7c7645c4faf7 100644 (file)
@@ -78,7 +78,7 @@ static void lookupsid_recv_domain(struct composite_context *ctx)
        if (!composite_is_ok(state->ctx)) return;
 
        ctx = wb_lsa_lookupsids_send(state, domain->lsa_pipe,
-                                    domain->lsa_policy, 1, &state->sid);
+                                    domain->lsa_policy_handle, 1, &state->sid);
        composite_continue(state->ctx, ctx, lookupsid_recv_names, state);
 }
 
index 219865b78c865d8f28c62b36079fa3f39f6a7370..b8b4fa8e4de0aa8738985f0d2b50482bbdbae92f 100644 (file)
@@ -5,7 +5,8 @@
    credentials. Try ntlmssp, schannel and anon in that order.
 
    Copyright (C) Volker Lendecke 2005
-   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
    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
@@ -26,6 +27,7 @@
 
 #include "libcli/raw/libcliraw.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "winbind/wb_server.h"
 
 /* Helper to initialize LSA with a specific auth methods. Verify by opening
  * the LSA policy. */
@@ -43,19 +45,15 @@ struct init_lsa_state {
 };
 
 static void init_lsa_recv_pipe(struct composite_context *ctx);
-static void init_lsa_recv_anon_bind(struct composite_context *ctx);
-static void init_lsa_recv_auth_bind(struct composite_context *ctx);
 static void init_lsa_recv_openpol(struct rpc_request *req);
 
 struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
-                                          struct smbcli_tree *tree,
-                                          uint8_t auth_type,
-                                          struct cli_credentials *creds)
+                                          struct wbsrv_domain *domain)
 {
        struct composite_context *result, *ctx;
        struct init_lsa_state *state;
 
-       result = composite_create(mem_ctx, tree->session->transport->socket->event.ctx);
+       result = composite_create(mem_ctx, domain->netlogon_pipe->conn->event_ctx);
        if (result == NULL) goto failed;
 
        state = talloc(result, struct init_lsa_state);
@@ -63,16 +61,11 @@ struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
        state->ctx = result;
        result->private_data = state;
 
-       state->auth_type = auth_type;
-       state->creds = creds;
-
-       state->lsa_pipe = dcerpc_pipe_init(state, result->event_ctx);
-       if (state->lsa_pipe == NULL) goto failed;
-
-       ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe, tree,
-                                       "\\lsarpc");
-       ctx->async.fn = init_lsa_recv_pipe;
-       ctx->async.private_data = state;
+       /* this will make the secondary connection on the same IPC$ share, 
+          secured with SPNEGO or NTLMSSP */
+       ctx = dcerpc_secondary_connection_send(domain->netlogon_pipe,
+                                              domain->lsa_binding);
+       composite_continue(state->ctx, ctx, init_lsa_recv_pipe, state);
        return result;
        
  failed:
@@ -82,81 +75,13 @@ struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
 
 static void init_lsa_recv_pipe(struct composite_context *ctx)
 {
-       struct init_lsa_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_lsa_state);
-
-       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
-       if (!composite_is_ok(state->ctx)) return;
-
-       switch (state->auth_type) {
-       case DCERPC_AUTH_TYPE_NONE:
-               ctx = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
-                                                &dcerpc_table_lsarpc);
-               composite_continue(state->ctx, ctx, init_lsa_recv_anon_bind,
-                                  state);
-               break;
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_SCHANNEL:
-       {
-               uint8_t auth_type;
-               if (lp_winbind_sealed_pipes()) {
-                       auth_type = DCERPC_AUTH_LEVEL_PRIVACY;
-               } else {
-                       auth_type = DCERPC_AUTH_LEVEL_INTEGRITY;
-               }
-               if (state->creds == NULL) {
-                       composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
-                       return;
-               }
-               ctx = dcerpc_bind_auth_send(state, state->lsa_pipe,
-                                           &dcerpc_table_lsarpc,
-                                           state->creds, state->auth_type,
-                                           auth_type,
-                                           NULL);
-               composite_continue(state->ctx, ctx, init_lsa_recv_auth_bind,
-                                  state);
-               break;
-       }
-       default:
-               composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
-       }
-}
-
-static void init_lsa_recv_anon_bind(struct composite_context *ctx)
-{
-       struct init_lsa_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_lsa_state);
        struct rpc_request *req;
-
-       state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
-       if (!composite_is_ok(state->ctx)) return;
-                       
-       state->handle = talloc(state, struct policy_handle);
-       if (composite_nomem(state->handle, state->ctx)) return;
-
-       state->openpolicy.in.system_name =
-               talloc_asprintf(state, "\\\\%s",
-                               dcerpc_server_name(state->lsa_pipe));
-       ZERO_STRUCT(state->objectattr);
-       state->openpolicy.in.attr = &state->objectattr;
-       state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       state->openpolicy.out.handle = state->handle;
-
-       req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
-                                         &state->openpolicy);
-       composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
-}
-
-static void init_lsa_recv_auth_bind(struct composite_context *ctx)
-{
        struct init_lsa_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct init_lsa_state);
-       struct rpc_request *req;
 
-       state->ctx->status = dcerpc_bind_auth_recv(ctx);
+       state->ctx->status = dcerpc_secondary_connection_recv(ctx, 
+                                                             &state->lsa_pipe);
        if (!composite_is_ok(state->ctx)) return;
                        
        state->handle = talloc(state, struct policy_handle);
@@ -206,150 +131,3 @@ NTSTATUS wb_init_lsa_recv(struct composite_context *c,
        return status;
 }
 
-
-/*
- * Connect to LSA using the credentials, try NTLMSSP and SCHANNEL using the
- * given credentials. If both fail or no credentials are available, fall back
- * to an anonymous bind.
- */
-
-struct connect_lsa_state {
-       struct composite_context *ctx;
-       struct smbcli_tree *tree;
-       struct cli_credentials *credentials;
-
-       uint8_t auth_type;
-       struct dcerpc_pipe *lsa_pipe;
-       struct policy_handle *lsa_policy;
-};
-
-static void connect_lsa_recv_ntlmssp(struct composite_context *ctx);
-static void connect_lsa_recv_schannel(struct composite_context *ctx);
-static void connect_lsa_recv_anon(struct composite_context *ctx);
-
-struct composite_context *wb_connect_lsa_send(TALLOC_CTX *mem_ctx,
-                                             struct smbcli_tree *tree,
-                                             struct cli_credentials *credentials)
-{
-       struct composite_context *result, *ctx;
-       struct connect_lsa_state *state;
-
-       result = composite_create(mem_ctx, tree->session->transport->socket->event.ctx);
-       if (result == NULL) goto failed;
-
-       state = talloc(result, struct connect_lsa_state);
-       if (state == NULL) goto failed;
-       state->ctx = result;
-       result->private_data = state;
-
-       state->tree = tree;
-       state->credentials = credentials;
-
-       if (credentials == NULL) {
-               ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NONE,
-                                      NULL);
-               if (ctx == NULL) goto failed;
-               ctx->async.fn = connect_lsa_recv_anon;
-               ctx->async.private_data = state;
-               return result;
-       }
-
-       ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NTLMSSP,
-                              credentials);
-       if (ctx == NULL) goto failed;
-       ctx->async.fn = connect_lsa_recv_ntlmssp;
-       ctx->async.private_data = state;
-       return result;
-
- failed:
-       talloc_free(result);
-       return NULL;
-}
-
-static void connect_lsa_recv_ntlmssp(struct composite_context *ctx)
-{
-       struct connect_lsa_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct connect_lsa_state);
-
-       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
-                                             &state->lsa_policy);
-
-       if (NT_STATUS_IS_OK(state->ctx->status)) {
-               state->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
-               composite_done(state->ctx);
-               return;
-       }
-
-       ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_SCHANNEL,
-                              state->credentials);
-       composite_continue(state->ctx, ctx,
-                          connect_lsa_recv_schannel, state);
-}
-
-static void connect_lsa_recv_schannel(struct composite_context *ctx)
-{
-       struct connect_lsa_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct connect_lsa_state);
-
-       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
-                                             &state->lsa_policy);
-
-       if (NT_STATUS_IS_OK(state->ctx->status)) {
-               state->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
-               composite_done(state->ctx);
-               return;
-       }
-
-       ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_NONE,
-                              state->credentials);
-       composite_continue(state->ctx, ctx,
-                          connect_lsa_recv_anon, state);
-}
-
-static void connect_lsa_recv_anon(struct composite_context *ctx)
-{
-       struct connect_lsa_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct connect_lsa_state);
-
-       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
-                                             &state->lsa_policy);
-       if (!composite_is_ok(state->ctx)) return;
-
-       state->auth_type = DCERPC_AUTH_TYPE_NONE;
-       composite_done(state->ctx);
-}
-
-NTSTATUS wb_connect_lsa_recv(struct composite_context *c,
-                            TALLOC_CTX *mem_ctx,
-                            uint8_t *auth_type,
-                            struct dcerpc_pipe **lsa_pipe,
-                            struct policy_handle **lsa_policy)
-{
-       NTSTATUS status = composite_wait(c);
-       if (NT_STATUS_IS_OK(status)) {
-               struct connect_lsa_state *state =
-                       talloc_get_type(c->private_data,
-                                       struct connect_lsa_state);
-               *auth_type = state->auth_type;
-               *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
-               *lsa_policy = talloc_steal(mem_ctx, state->lsa_policy);
-       }
-       talloc_free(c);
-       return status;
-}
-
-NTSTATUS wb_connect_lsa(TALLOC_CTX *mem_ctx,
-                       struct smbcli_tree *tree,
-                       struct cli_credentials *credentials,
-                       uint8_t *auth_type,
-                       struct dcerpc_pipe **lsa_pipe,
-                       struct policy_handle **lsa_policy)
-{
-       struct composite_context *c;
-       c = wb_connect_lsa_send(mem_ctx, tree, credentials);
-       return wb_connect_lsa_recv(c, mem_ctx, auth_type, lsa_pipe,
-                                  lsa_policy);
-}
index 4423e3e91d8e4965033b1af4ac4d1ea122f2bba9..ab34e9663552bc60e2c9dca20c581a0f63653355 100644 (file)
@@ -1,10 +1,10 @@
 /* 
    Unix SMB/CIFS implementation.
 
-   Connect to the SAMR pipe, given an smbcli_tree and possibly some
-   credentials. Try ntlmssp, schannel and anon in that order.
+   Connect to the SAMR pipe, and return connection and domain handles.
 
    Copyright (C) Volker Lendecke 2005
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
    
    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
@@ -27,6 +27,7 @@
 #include "libcli/raw/libcliraw.h"
 #include "libcli/security/security.h"
 #include "librpc/gen_ndr/ndr_samr_c.h"
+#include "winbind/wb_server.h"
 
 
 /* Helper to initialize SAMR with a specific auth methods. Verify by opening
@@ -34,8 +35,6 @@
 
 struct connect_samr_state {
        struct composite_context *ctx;
-       uint8_t auth_type;
-       struct cli_credentials *creds;
        struct dom_sid *sid;
 
        struct dcerpc_pipe *samr_pipe;
@@ -47,21 +46,16 @@ struct connect_samr_state {
 };
 
 static void connect_samr_recv_pipe(struct composite_context *ctx);
-static void connect_samr_recv_anon_bind(struct composite_context *ctx);
-static void connect_samr_recv_auth_bind(struct composite_context *ctx);
 static void connect_samr_recv_conn(struct rpc_request *req);
 static void connect_samr_recv_open(struct rpc_request *req);
 
-struct composite_context *wb_connect_sam_send(TALLOC_CTX *mem_ctx,
-                                             struct smbcli_tree *tree,
-                                             uint8_t auth_type,
-                                             struct cli_credentials *creds,
-                                             const struct dom_sid *domain_sid)
+struct composite_context *wb_connect_samr_send(TALLOC_CTX *mem_ctx,
+                                          struct wbsrv_domain *domain)
 {
        struct composite_context *result, *ctx;
        struct connect_samr_state *state;
 
-       result = composite_create(mem_ctx, tree->session->transport->socket->event.ctx);
+       result = composite_create(mem_ctx, domain->netlogon_pipe->conn->event_ctx);
        if (result == NULL) goto failed;
 
        state = talloc(result, struct connect_samr_state);
@@ -69,18 +63,14 @@ struct composite_context *wb_connect_sam_send(TALLOC_CTX *mem_ctx,
        state->ctx = result;
        result->private_data = state;
 
-       state->auth_type = auth_type;
-       state->creds = creds;
-       state->sid = dom_sid_dup(state, domain_sid);
+       state->sid = dom_sid_dup(state, domain->info->sid);
        if (state->sid == NULL) goto failed;
 
-       state->samr_pipe = dcerpc_pipe_init(state, result->event_ctx);
-       if (state->samr_pipe == NULL) goto failed;
-
-       ctx = dcerpc_pipe_open_smb_send(state->samr_pipe, tree,
-                                       "\\samr");
-       ctx->async.fn = connect_samr_recv_pipe;
-       ctx->async.private_data = state;
+       /* this will make the secondary connection on the same IPC$ share, 
+          secured with SPNEGO, NTLMSSP or SCHANNEL */
+       ctx = dcerpc_secondary_connection_send(domain->netlogon_pipe,
+                                              domain->samr_binding);
+       composite_continue(state->ctx, ctx, connect_samr_recv_pipe, state);
        return result;
        
  failed:
@@ -90,78 +80,13 @@ struct composite_context *wb_connect_sam_send(TALLOC_CTX *mem_ctx,
 
 static void connect_samr_recv_pipe(struct composite_context *ctx)
 {
-       struct connect_samr_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct connect_samr_state);
-
-       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
-       if (!composite_is_ok(state->ctx)) return;
-
-       switch (state->auth_type) {
-       case DCERPC_AUTH_TYPE_NONE:
-               ctx = dcerpc_bind_auth_none_send(state, state->samr_pipe,
-                                                &dcerpc_table_samr);
-               composite_continue(state->ctx, ctx,
-                                  connect_samr_recv_anon_bind, state);
-               break;
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_SCHANNEL:
-       {
-               uint8_t auth_type;
-               if (lp_winbind_sealed_pipes()) {
-                       auth_type = DCERPC_AUTH_LEVEL_PRIVACY;
-               } else {
-                       auth_type = DCERPC_AUTH_LEVEL_INTEGRITY;
-               }
-               if (state->creds == NULL) {
-                       composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
-                       return;
-               }
-               ctx = dcerpc_bind_auth_send(state, state->samr_pipe,
-                                           &dcerpc_table_samr,
-                                           state->creds, state->auth_type,
-                                           auth_type,
-                                           NULL);
-               composite_continue(state->ctx, ctx,
-                                  connect_samr_recv_auth_bind, state);
-               break;
-       }
-       default:
-               composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
-       }
-}
-
-static void connect_samr_recv_anon_bind(struct composite_context *ctx)
-{
-       struct connect_samr_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct connect_samr_state);
        struct rpc_request *req;
-
-       state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
-       if (!composite_is_ok(state->ctx)) return;
-                       
-       state->connect_handle = talloc(state, struct policy_handle);
-       if (composite_nomem(state->connect_handle, state->ctx)) return;
-
-       state->c.in.system_name =
-               talloc_asprintf(state, "\\\\%s",
-                               dcerpc_server_name(state->samr_pipe));
-       state->c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       state->c.out.connect_handle = state->connect_handle;
-
-       req = dcerpc_samr_Connect2_send(state->samr_pipe, state, &state->c);
-       composite_continue_rpc(state->ctx, req, connect_samr_recv_conn, state);
-}
-
-static void connect_samr_recv_auth_bind(struct composite_context *ctx)
-{
        struct connect_samr_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct connect_samr_state);
-       struct rpc_request *req;
 
-       state->ctx->status = dcerpc_bind_auth_recv(ctx);
+       state->ctx->status = dcerpc_secondary_connection_recv(ctx, 
+                                                             &state->samr_pipe);
        if (!composite_is_ok(state->ctx)) return;
                        
        state->connect_handle = talloc(state, struct policy_handle);
@@ -175,6 +100,7 @@ static void connect_samr_recv_auth_bind(struct composite_context *ctx)
 
        req = dcerpc_samr_Connect2_send(state->samr_pipe, state, &state->c);
        composite_continue_rpc(state->ctx, req, connect_samr_recv_conn, state);
+       return;
 }
 
 static void connect_samr_recv_conn(struct rpc_request *req)
@@ -215,7 +141,7 @@ static void connect_samr_recv_open(struct rpc_request *req)
        composite_done(state->ctx);
 }
 
-NTSTATUS wb_connect_sam_recv(struct composite_context *c,
+NTSTATUS wb_connect_samr_recv(struct composite_context *c,
                             TALLOC_CTX *mem_ctx,
                             struct dcerpc_pipe **samr_pipe,
                             struct policy_handle **connect_handle,
@@ -234,18 +160,3 @@ NTSTATUS wb_connect_sam_recv(struct composite_context *c,
        return status;
 }
 
-NTSTATUS wb_connect_sam(TALLOC_CTX *mem_ctx,
-                       struct smbcli_tree *tree,
-                       uint8_t auth_type,
-                       struct cli_credentials *creds,
-                       const struct dom_sid *domain_sid,
-                       struct dcerpc_pipe **samr_pipe,
-                       struct policy_handle **connect_handle,
-                       struct policy_handle **domain_handle)
-{
-       struct composite_context *c =
-               wb_connect_sam_send(mem_ctx, tree, auth_type, creds,
-                                   domain_sid);
-       return wb_connect_sam_recv(c, mem_ctx, samr_pipe, connect_handle,
-                                  domain_handle);
-}
index 3f28c3137238e65309b8b1f59946c0c71342c089..a25029eb21e7ec210912fcafa551e7ef588bf702 100644 (file)
@@ -4,7 +4,8 @@
    A composite API for initializing a domain
 
    Copyright (C) Volker Lendecke 2005
-   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
    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
@@ -29,6 +30,7 @@
 #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/auth/credentials.h"
 #include "libcli/security/security.h"
 /*
  * Initialize a domain:
  *
- * - With schannel credentials, try to open the SMB connection with the
- *   machine creds. This works against W2k3SP1 with an NTLMSSP session
- *   setup. Fall back to anonymous.
+ * - With schannel credentials, try to open the SMB connection and
+ *   NETLOGON pipe with the machine creds. This works against W2k3SP1
+ *   with an NTLMSSP session setup. Fall back to anonymous (for the CIFS level).
  *
  * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
  *   pipe.
  *
- * - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
- *   to schannel and then to anon bind.
+ * - Open LSA. If we have machine creds, try to open with SPNEGO or NTLMSSP. Fall back
+ *   to schannel.
  *
  * - With queryinfopolicy, verify that we're talking to the right domain
  *
@@ -64,20 +66,47 @@ struct init_domain_state {
        struct wbsrv_domain *domain;
        struct wbsrv_service *service;
 
-       struct smb_composite_connect conn;
-
+       struct lsa_ObjectAttribute objectattr;
+       struct lsa_OpenPolicy2 lsa_openpolicy;
        struct lsa_QueryInfoPolicy queryinfo;
 };
 
-static void init_domain_recv_tree(struct composite_context *ctx);
-static void init_domain_recv_netlogoncreds(struct composite_context *ctx);
 static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
-static void init_domain_recv_schannel(struct composite_context *ctx);
-static void init_domain_recv_lsa(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_samr(struct composite_context *ctx);
 
+static struct dcerpc_binding *init_domain_binding(struct init_domain_state *state, 
+                                                 const struct dcerpc_interface_table *table) 
+{
+       struct dcerpc_binding *binding;
+       NTSTATUS status;
+       /* Make a binding string */
+       {
+               char *s = talloc_asprintf(state, "ncacn_np:%s", state->domain->info->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->info->dc_name;
+       binding->host = state->domain->info->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);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NULL;
+       }
+
+       return binding;
+}
+
 struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
                                              struct wbsrv_service *service,
                                              struct wb_dom_info *dom_info)
@@ -101,153 +130,178 @@ 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;
 
+       /* Create a credentials structure */
        state->domain->schannel_creds = cli_credentials_init(state->domain);
        if (state->domain->schannel_creds == NULL) goto failed;
 
+       cli_credentials_set_event_context(state->domain->schannel_creds, service->task->event_ctx);
+
        cli_credentials_set_conf(state->domain->schannel_creds);
+
+       /* Connect the machine account to the credentials */
        state->ctx->status =
                cli_credentials_set_machine_account(state->domain->
                                                    schannel_creds);
        if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
 
-       state->conn.in.dest_host = dom_info->dc_address;
-       state->conn.in.port = 0;
-       state->conn.in.called_name = dom_info->dc_name;
-       state->conn.in.service = "IPC$";
-       state->conn.in.service_type = "IPC";
-       state->conn.in.workgroup = dom_info->name;
-       state->conn.in.credentials = state->domain->schannel_creds;
+       state->domain->netlogon_binding = init_domain_binding(state, &dcerpc_table_netlogon);
 
-       state->conn.in.fallback_to_anonymous = True;
+       state->domain->netlogon_pipe = NULL;
 
-       ctx = smb_composite_connect_send(&state->conn, state->domain,
-                                        result->event_ctx);
-       if (ctx == NULL) goto failed;
+       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)))) {
+               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()) {
+                       state->domain->netlogon_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
+               } else {
+                       state->domain->netlogon_binding->flags |= (DCERPC_SIGN);
+               }
+       }
 
-       ctx->async.fn = init_domain_recv_tree;
-       ctx->async.private_data = state;
-       return result;
+       /* 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);
+       
+       if (composite_nomem(ctx, state->ctx)) {
+               goto failed;
+       }
+       
+       composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
+                          state);
+       return result;
  failed:
        talloc_free(result);
        return NULL;
 }
 
-static void init_domain_recv_tree(struct composite_context *ctx)
+/* Having make a netlogon connection (possibly secured with schannel),
+ * make an LSA connection to the same DC, on the same IPC$ share */
+static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
 {
        struct init_domain_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct init_domain_state);
-       state->ctx->status = smb_composite_connect_recv(ctx, state);
-       if (!composite_is_ok(state->ctx)) return;
 
-       if ((state->domain->schannel_creds != NULL) &&
-           (!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)))) {
-               ctx = wb_get_schannel_creds_send(state,
-                                                state->domain->schannel_creds,
-                                                state->conn.out.tree,
-                                                state->ctx->event_ctx);
-               composite_continue(state->ctx, ctx,
-                                  init_domain_recv_netlogoncreds, state);
+       state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state, 
+                                                  &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);
 
-       ctx = wb_connect_lsa_send(state, state->conn.out.tree, NULL);
-       composite_continue(state->ctx, ctx, init_domain_recv_lsa, state);
-}
-
-static void init_domain_recv_netlogoncreds(struct composite_context *ctx)
-{
-       struct init_domain_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_domain_state);
-       struct dcerpc_pipe *auth2_pipe;
-       struct smbcli_tree *tree = NULL;
-
-       state->ctx->status =
-               wb_get_schannel_creds_recv(ctx, state, &auth2_pipe);
-       if (!composite_is_ok(state->ctx)) return;
+       state->domain->lsa_binding = init_domain_binding(state, &dcerpc_table_lsarpc);
 
-       if (!lp_winbind_sealed_pipes()) {
-               state->domain->netlogon_pipe = talloc_reference(state->domain,
-                                                               auth2_pipe);
-               ctx = wb_connect_lsa_send(state, state->conn.out.tree, NULL);
-               composite_continue(state->ctx, ctx, init_domain_recv_lsa,
-                                  state);
-               return;
+       /* For debugging, it can be a real pain if all the traffic is encrypted */
+       if (lp_winbind_sealed_pipes()) {
+               state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
+       } else {
+               state->domain->lsa_binding->flags |= (DCERPC_SIGN);
        }
 
-       state->domain->netlogon_pipe =
-               dcerpc_pipe_init(state->domain, state->ctx->event_ctx);
-       if (composite_nomem(state->domain->netlogon_pipe, state->ctx)) return;
-
-       tree = dcerpc_smb_tree(auth2_pipe->conn);
-       if (tree == NULL) {
-               composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
-               return;
-       }
+       state->domain->lsa_pipe = NULL;
 
-       ctx = dcerpc_pipe_open_smb_send(state->domain->netlogon_pipe,
-                                       tree, "\\netlogon");
-       composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
-                          state);
+       /* 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);
+       composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
 }
 
-static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
+static bool retry_with_schannel(struct init_domain_state *state, 
+                               struct dcerpc_binding *binding,
+                               void (*continuation)(struct composite_context *))
+{
+       struct composite_context *ctx;
+       if (state->domain->netlogon_binding->flags & DCERPC_SCHANNEL 
+           && !(binding->flags & DCERPC_SCHANNEL)) {
+               /* Opening a policy handle failed, perhaps it was
+                * because we don't get a 'wrong password' error on
+                * NTLMSSP binds */
+
+               /* Try again with schannel */
+               binding->flags |= DCERPC_SCHANNEL;
+
+               /* Try again, likewise on the same IPC$ share, 
+                  secured with SCHANNEL */
+               ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe,
+                                                      binding);
+               composite_continue(state->ctx, ctx, continuation, state);               
+               return true;
+       } else {
+               return false;
+       }
+}
+/* We should now have either an authenticated LSA pipe, or an error.  
+ * On success, open a policy handle
+ */    
+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);
 
-       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
+       state->ctx->status = dcerpc_secondary_connection_recv(ctx, 
+                                                             &state->domain->lsa_pipe);
+       if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) {
+               if (retry_with_schannel(state, state->domain->lsa_binding, 
+                                       init_domain_recv_lsa_pipe)) {
+                       return;
+               }
+       }
        if (!composite_is_ok(state->ctx)) return;
 
-       state->domain->netlogon_pipe->conn->flags |=
-               (DCERPC_SIGN | DCERPC_SEAL);
-       ctx = dcerpc_bind_auth_send(state, state->domain->netlogon_pipe,
-                                   &dcerpc_table_netlogon,
-                                   state->domain->schannel_creds,
-                                   DCERPC_AUTH_TYPE_SCHANNEL,
-                                   DCERPC_AUTH_LEVEL_PRIVACY,
-                                   NULL);
-       composite_continue(state->ctx, ctx, init_domain_recv_schannel, state);
-}
+       talloc_steal(state->domain, state->domain->lsa_pipe);
+       talloc_steal(state->domain->lsa_pipe, state->domain->lsa_binding);
 
-static void init_domain_recv_schannel(struct composite_context *ctx)
-{
-       struct init_domain_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_domain_state);
+       state->domain->lsa_policy_handle = talloc(state, struct policy_handle);
+       if (composite_nomem(state->domain->lsa_policy_handle, state->ctx)) return;
 
-       state->ctx->status = dcerpc_bind_auth_recv(ctx);
-       if (!composite_is_ok(state->ctx)) return;
+       state->lsa_openpolicy.in.system_name =
+               talloc_asprintf(state, "\\\\%s",
+                               dcerpc_server_name(state->domain->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);
 
-       ctx = wb_connect_lsa_send(state, state->conn.out.tree,
-                                 state->domain->schannel_creds);
-       composite_continue(state->ctx, ctx, init_domain_recv_lsa, state);
+       composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state);
 }
 
-static void init_domain_recv_lsa(struct composite_context *ctx)
+/* 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)
 {
        struct init_domain_state *state =
-               talloc_get_type(ctx->async.private_data,
+               talloc_get_type(req->async.private_data,
                                struct init_domain_state);
 
-       struct rpc_request *req;
-
-       state->ctx->status = wb_connect_lsa_recv(ctx, state->domain,
-                                                &state->domain->lsa_auth_type,
-                                                &state->domain->lsa_pipe,
-                                                &state->domain->lsa_policy);
+       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))) {
+               if (retry_with_schannel(state, state->domain->lsa_binding, 
+                                       init_domain_recv_lsa_pipe)) {
+                       return;
+               }
+       }
+       if (!composite_is_ok(state->ctx)) return;
+       state->ctx->status = state->lsa_openpolicy.out.result;
        if (!composite_is_ok(state->ctx)) return;
 
-       /* Give the tree to the pipes. */
-       talloc_unlink(state, state->conn.out.tree);
-
-       state->queryinfo.in.handle = state->domain->lsa_policy;
+       state->queryinfo.in.handle = state->domain->lsa_policy_handle;
        state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
 
        req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->lsa_pipe, state,
@@ -262,7 +316,6 @@ static void init_domain_recv_queryinfo(struct rpc_request *req)
                talloc_get_type(req->async.private_data, struct init_domain_state);
        struct lsa_DomainInfo *dominfo;
        struct composite_context *ctx;
-       const char *ldap_url;
 
        state->ctx->status = dcerpc_ndr_request_recv(req);
        if (!composite_is_ok(state->ctx)) return;
@@ -289,6 +342,36 @@ static void init_domain_recv_queryinfo(struct rpc_request *req)
                return;
        }
 
+       state->domain->samr_binding = init_domain_binding(state, &dcerpc_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;
+
+       ctx = wb_connect_samr_send(state, state->domain);
+       composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
+}
+
+/* Recv the SAMR details (SamrConnect and SamrOpenDomain handle) and
+ * 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);
+       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);
@@ -319,28 +402,6 @@ static void init_domain_recv_ldapconn(struct composite_context *ctx)
                          nt_errstr(state->ctx->status)));
        }
 
-       state->domain->samr_pipe =
-               dcerpc_pipe_init(state->domain, state->ctx->event_ctx);
-       if (composite_nomem(state->domain->samr_pipe, state->ctx)) return;
-
-       ctx = wb_connect_sam_send(state, state->conn.out.tree,
-                                 state->domain->lsa_auth_type,
-                                 state->domain->schannel_creds,
-                                 state->domain->info->sid);
-       composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
-}
-
-static void init_domain_recv_samr(struct composite_context *ctx)
-{
-       struct init_domain_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct init_domain_state);
-
-       state->ctx->status = wb_connect_sam_recv(
-               ctx, state->domain, &state->domain->samr_pipe,
-               &state->domain->samr_handle, &state->domain->domain_handle);
-       if (!composite_is_ok(state->ctx)) return;
-
        composite_done(state->ctx);
 }
 
index 42f11157d226a4dd7ff86b53c7dd6a2db8d51bbc..7d334193d4b0ed7a7daa24b923eea362f8723d8f 100644 (file)
@@ -60,16 +60,18 @@ struct wbsrv_domain {
        struct wb_dom_info *info;
 
        struct dcerpc_pipe *lsa_pipe;
-       struct policy_handle *lsa_policy;
-       uint8_t lsa_auth_type;
+       struct policy_handle *lsa_policy_handle;
+       struct dcerpc_binding *lsa_binding;
 
        struct dcerpc_pipe *samr_pipe;
        struct policy_handle *samr_handle;
        struct policy_handle *domain_handle;
+       struct dcerpc_binding *samr_binding;
 
        struct ldap_connection *ldap_conn;
 
        struct dcerpc_pipe *netlogon_pipe;
+       struct dcerpc_binding *netlogon_binding;
        struct cli_credentials *schannel_creds;
 };