s4:librpc/rpc: remove unused dcerpc_secondary_smb_send/recv()
[metze/samba/wip.git] / source4 / librpc / rpc / dcerpc_smb.c
index 51722c8a04e6c9158dba3fd079266dbdfaf0547b..1487bde75a5890f213cc3da8f9970bc7092770f1 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 "system/filesys.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/smb/smb_constants.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "libcli/smb/tstream_smbXcli_np.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/smb2/smb2.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "libcli/composite/composite.h"
 
 /* transport private information used by SMB pipe transport */
 struct smb_private {
-       uint16_t fnum;
-       struct smbcli_tree *tree;
+       DATA_BLOB session_key;
 };
 
-static struct smbcli_request *dcerpc_raw_send(struct dcerpc_pipe *p, DATA_BLOB *blob)
-{
-       struct smb_private *smb = p->transport.private;
-       struct smb_trans2 trans;
-       uint16_t setup[2];
-       struct smbcli_request *req;
-       TALLOC_CTX *mem_ctx;
-
-       mem_ctx = talloc_init("dcerpc_raw_send");
-       if (!mem_ctx) return NULL;
-
-       trans.in.data = *blob;
-       trans.in.params = data_blob(NULL, 0);
-       
-       setup[0] = TRANSACT_DCERPCCMD;
-       setup[1] = smb->fnum;
-
-       trans.in.max_param = 0;
-       trans.in.max_data = 0x8000;
-       trans.in.max_setup = 0;
-       trans.in.setup_count = 2;
-       trans.in.flags = 0;
-       trans.in.timeout = 0;
-       trans.in.setup = setup;
-       trans.in.trans_name = "\\PIPE\\";
-
-       req = smb_raw_trans_send(smb->tree, &trans);
-
-       talloc_destroy(mem_ctx);
-
-       return req;
-}
-
-
-static NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p, 
-                               struct smbcli_request *req,
-                               TALLOC_CTX *mem_ctx,
-                               DATA_BLOB *blob)
+/*
+  fetch the user session key 
+*/
+static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
 {
-       struct smb_private *smb = p->transport.private;
-       struct smb_trans2 trans;
-       NTSTATUS status;
-       uint16_t frag_length;
-       DATA_BLOB payload;
-
-       status = smb_raw_trans_recv(req, mem_ctx, &trans);
-
-       /* STATUS_BUFFER_OVERFLOW means that there is more data
-          available via SMBreadX */
-       if (!NT_STATUS_IS_OK(status) && 
-           !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
-               return status;
-       }
-
-       payload = trans.out.data;
+       struct smb_private *smb = talloc_get_type_abort(
+               c->transport.private_data, struct smb_private);
 
-       if (trans.out.data.length < 16 || 
-           !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
-               goto done;
-       }
+       if (smb == NULL) return NT_STATUS_CONNECTION_DISCONNECTED;
 
-       /* we might have recieved a partial fragment, in which case we
-          need to pull the rest of it */
-       frag_length = dcerpc_get_frag_length(&payload);
-       if (frag_length <= payload.length) {
-               goto done;
+       if (smb->session_key.length == 0) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
        }
 
-       /* make sure the payload can hold the whole fragment */
-       payload.data = talloc_realloc(mem_ctx, payload.data, frag_length);
-       if (!payload.data) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* the rest of the data is available via SMBreadX */
-       while (frag_length > payload.length) {
-               uint32_t n;
-               union smb_read io;
-
-               n = frag_length - payload.length;
-               if (n > 0xFF00) {
-                       n = 0xFF00;
-               }
-
-               io.generic.level = RAW_READ_READX;
-               io.readx.in.fnum = smb->fnum;
-               io.readx.in.mincnt = n;
-               io.readx.in.maxcnt = n;
-               io.readx.in.offset = 0;
-               io.readx.in.remaining = 0;
-               io.readx.out.data = payload.data + payload.length;
-               status = smb_raw_read(smb->tree, &io);
-               if (!NT_STATUS_IS_OK(status) &&
-                   !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
-                       break;
-               }
-               
-               n = io.readx.out.nread;
-               if (n == 0) {
-                       status = NT_STATUS_UNSUCCESSFUL;
-                       break;
-               }
-               
-               payload.length += n;
+       *session_key = smb->session_key;
+       return NT_STATUS_OK;
+}
 
-               /* if the SMBreadX returns NT_STATUS_OK then there
-                  isn't any more data to be read */
-               if (NT_STATUS_IS_OK(status)) {
-                       break;
-               }
-       }
+struct dcerpc_pipe_open_smb_state {
+       struct dcecli_connection *c;
+       struct composite_context *ctx;
 
-done:
-       if (blob) {
-               *blob = payload;
-       }
+       const char *fname;
 
-       return status;
-}
+       struct smb_private *smb;
+};
 
-static NTSTATUS smb_full_request(struct dcerpc_pipe *p, 
-                                TALLOC_CTX *mem_ctx,
-                                DATA_BLOB *request_blob,
-                                DATA_BLOB *reply_blob)
-{
-       struct smbcli_request *req;
-       req = dcerpc_raw_send(p, request_blob);
-       return dcerpc_raw_recv(p, req, mem_ctx, reply_blob);
-}
-             
+static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq);
 
-/* 
-   retrieve a secondary pdu from a pipe 
-*/
-static NTSTATUS smb_secondary_request(struct dcerpc_pipe *p, 
-                              TALLOC_CTX *mem_ctx,
-                              DATA_BLOB *blob)
+struct composite_context *dcerpc_pipe_open_smb_send(struct dcecli_connection *c,
+                                               struct smbXcli_conn *conn,
+                                               struct smbXcli_session *session,
+                                               struct smbXcli_tcon *tcon,
+                                               uint32_t timeout_msec,
+                                               const char *pipe_name)
 {
-       struct smb_private *smb = p->transport.private;
-       union smb_read io;
-       uint32_t n = 0x2000;
-       uint32_t frag_length;
-       NTSTATUS status;
+       struct composite_context *ctx;
+       struct dcerpc_pipe_open_smb_state *state;
+       uint16_t pid = 0;
+       struct tevent_req *subreq;
 
-       *blob = data_blob_talloc(mem_ctx, NULL, n);
-       if (!blob->data) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       io.generic.level = RAW_READ_READX;
-       io.readx.in.fnum = smb->fnum;
-       io.readx.in.mincnt = n;
-       io.readx.in.maxcnt = n;
-       io.readx.in.offset = 0;
-       io.readx.in.remaining = 0;
-       io.readx.out.data = blob->data;
-
-       status = smb_raw_read(smb->tree, &io);
-       if (!NT_STATUS_IS_OK(status) &&
-           !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
-               return status;
-       }
+       ctx = composite_create(c, c->event_ctx);
+       if (ctx == NULL) return NULL;
 
-       blob->length = io.readx.out.nread;
+       state = talloc(ctx, struct dcerpc_pipe_open_smb_state);
+       if (composite_nomem(state, ctx)) return ctx;
+       ctx->private_data = state;
 
-       if (blob->length < 16) {
-               return status;
-       }
+       state->c = c;
+       state->ctx = ctx;
 
-       frag_length = dcerpc_get_frag_length(blob);
-       if (frag_length <= blob->length) {
-               return status;
+       if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) || 
+           (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
+               pipe_name += 6;
        }
-
-       blob->data = talloc_realloc(mem_ctx, blob->data, frag_length);
-       if (!blob->data) {
-               return NT_STATUS_NO_MEMORY;
+       if ((strncasecmp(pipe_name, "/", 1) == 0) ||
+           (strncasecmp(pipe_name, "\\", 1) == 0)) {
+               pipe_name += 1;
        }
+       state->fname = talloc_strdup(state, pipe_name);
+       if (composite_nomem(state->fname, ctx)) return ctx;
 
-       while (frag_length > blob->length &&
-              NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+       state->smb = talloc_zero(state, struct smb_private);
+       if (composite_nomem(state->smb, ctx)) return ctx;
 
-               n = frag_length - blob->length;
-               if (n > 0xFF00) {
-                       n = 0xFF00;
-               }
+       state->c->server_name = strupper_talloc(state->c,
+               smbXcli_conn_remote_name(conn));
+       if (composite_nomem(state->c->server_name, ctx)) return ctx;
 
-               io.readx.in.mincnt = n;
-               io.readx.in.maxcnt = n;
-               io.readx.out.data = blob->data + blob->length;
-               status = smb_raw_read(smb->tree, &io);
-
-               if (!NT_STATUS_IS_OK(status) &&
-                   !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
-                       return status;
-               }
-               
-               n = io.readx.out.nread;
-               blob->length += n;
+       ctx->status = smbXcli_session_application_key(session,
+                                                     state->smb,
+                                                     &state->smb->session_key);
+       if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_NO_USER_SESSION_KEY)) {
+               state->smb->session_key = data_blob_null;
+               ctx->status = NT_STATUS_OK;
        }
+       if (!composite_is_ok(ctx)) return ctx;
 
-       return status;
-}
+       subreq = tstream_smbXcli_np_open_send(state, c->event_ctx,
+                                             conn, session, tcon, pid,
+                                             timeout_msec, state->fname);
+       if (composite_nomem(subreq, ctx)) return ctx;
+       tevent_req_set_callback(subreq, dcerpc_pipe_open_smb_done, state);
 
-
-/* 
-   send an initial pdu in a multi-pdu sequence
-*/
-static NTSTATUS smb_initial_request(struct dcerpc_pipe *p, 
-                                   TALLOC_CTX *mem_ctx,
-                                   DATA_BLOB *blob)
-{
-       struct smb_private *smb = p->transport.private;
-       union smb_write io;
-       NTSTATUS status;
-
-       io.generic.level = RAW_WRITE_WRITEX;
-       io.writex.in.fnum = smb->fnum;
-       io.writex.in.offset = 0;
-       io.writex.in.wmode = PIPE_START_MESSAGE;
-       io.writex.in.remaining = blob->length;
-       io.writex.in.count = blob->length;
-       io.writex.in.data = blob->data;
-
-       status = smb_raw_write(smb->tree, &io);
-       if (NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /* make sure it accepted it all */
-       if (io.writex.out.nwritten != blob->length) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       return status;
-}
-
-
-/* 
-   shutdown SMB pipe connection
-*/
-static NTSTATUS smb_shutdown_pipe(struct dcerpc_pipe *p)
-{
-       struct smb_private *smb = p->transport.private;
-       union smb_close c;
-
-       /* maybe we're still starting up */
-       if (!smb) return NT_STATUS_OK;
-
-       c.close.level = RAW_CLOSE_CLOSE;
-       c.close.in.fnum = smb->fnum;
-       c.close.in.write_time = 0;
-       smb_raw_close(smb->tree, &c);
-       smbcli_tree_close(smb->tree);
-
-       return NT_STATUS_OK;
+       return ctx;
 }
 
-/*
-  return SMB server name
-*/
-static const char *smb_peer_name(struct dcerpc_pipe *p)
+static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq)
 {
-       struct smb_private *smb = p->transport.private;
-       return smb->tree->session->transport->called.name;
-}
+       struct dcerpc_pipe_open_smb_state *state =
+               tevent_req_callback_data(subreq,
+               struct dcerpc_pipe_open_smb_state);
+       struct composite_context *ctx = state->ctx;
+       struct dcecli_connection *c = state->c;
+
+       ctx->status = tstream_smbXcli_np_open_recv(subreq,
+                                                  state->smb,
+                                                  &state->c->transport.stream);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(ctx)) return;
+
+       state->c->transport.write_queue =
+               tevent_queue_create(state->c, "dcerpc_smb write queue");
+       if (composite_nomem(state->c->transport.write_queue, ctx)) return;
 
-/* 
-   open a rpc connection to a named pipe 
-*/
-NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, 
-                             struct smbcli_tree *tree,
-                             const char *pipe_name)
-{
-       struct smb_private *smb;
-        NTSTATUS status;
-       char *name = NULL;
-       union smb_open io;
-       TALLOC_CTX *mem_ctx;
-
-       asprintf(&name, "\\%s", pipe_name);
-       if (!name) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       io.ntcreatex.level = RAW_OPEN_NTCREATEX;
-       io.ntcreatex.in.flags = 0;
-       io.ntcreatex.in.root_fid = 0;
-       io.ntcreatex.in.access_mask = 
-               STD_RIGHT_READ_CONTROL_ACCESS | 
-               SA_RIGHT_FILE_WRITE_ATTRIBUTES | 
-               SA_RIGHT_FILE_WRITE_EA | 
-               GENERIC_RIGHTS_FILE_READ |
-               GENERIC_RIGHTS_FILE_WRITE;
-       io.ntcreatex.in.file_attr = 0;
-       io.ntcreatex.in.alloc_size = 0;
-       io.ntcreatex.in.share_access = 
-               NTCREATEX_SHARE_ACCESS_READ |
-               NTCREATEX_SHARE_ACCESS_WRITE;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
-       io.ntcreatex.in.create_options = 0;
-       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
-       io.ntcreatex.in.security_flags = 0;
-       io.ntcreatex.in.fname = name;
-
-       mem_ctx = talloc_init("torture_rpc_connection");
-       if (!mem_ctx) {
-               free(name);
-               return NT_STATUS_NO_MEMORY;
-       }
-       status = smb_raw_open(tree, mem_ctx, &io);
-       free(name);
-       talloc_destroy(mem_ctx);
-
-       if (!NT_STATUS_IS_OK(status)) {
-                return status;
-        }
-
-        if (!(*p = dcerpc_pipe_init())) {
-                return NT_STATUS_NO_MEMORY;
-       }
        /*
          fill in the transport methods
        */
-       (*p)->transport.transport = NCACN_NP;
-       (*p)->transport.private = NULL;
-       (*p)->transport.full_request = smb_full_request;
-       (*p)->transport.secondary_request = smb_secondary_request;
-       (*p)->transport.initial_request = smb_initial_request;
-       (*p)->transport.shutdown_pipe = smb_shutdown_pipe;
-       (*p)->transport.peer_name = smb_peer_name;
-       
-       smb = talloc((*p)->mem_ctx, sizeof(*smb));
-       if (!smb) {
-               dcerpc_pipe_close(*p);
-               return NT_STATUS_NO_MEMORY;
-       }
+       c->transport.transport       = NCACN_NP;
+       c->transport.private_data    = NULL;
 
-       smb->fnum = io.ntcreatex.out.fnum;
-       smb->tree = tree;
+       /*
+        * Windows uses 4280 for ncacn_np,
+        * so we also use it, this is what our
+        * tstream_smbXcli_np code relies on.
+        */
+       c->srv_max_xmit_frag = 4280;
+       c->srv_max_recv_frag = 4280;
 
-       (*p)->transport.private = smb;
-       tree->reference_count++;
+       /* Over-ride the default session key with the SMB session key */
+       c->security_state.session_key = smb_session_key;
 
-        return NT_STATUS_OK;
+       c->transport.private_data = talloc_move(c, &state->smb);
+
+       composite_done(ctx);
 }
 
-/*
-  return the SMB tree used for a dcerpc over SMB pipe
-*/
-struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_pipe *p)
+NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
 {
-       struct smb_private *smb = p->transport.private;
-
-       if (p->transport.transport != NCACN_NP) {
-               return NULL;
-       }
-
-       return smb->tree;
+       NTSTATUS status = composite_wait(c);
+       talloc_free(c);
+       return status;
 }