]> git.samba.org - kai/samba-autobuild/.git/blobdiff - source4/librpc/rpc/dcerpc_smb.c
r23792: convert Samba4 to GPLv3
[kai/samba-autobuild/.git] / source4 / librpc / rpc / dcerpc_smb.c
index 594feb8d643d37c0f40359d0e0459c1e659f1dfa..6b43de3358ace0020b7c7bfd0ceec5398bcaa338 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,
@@ -17,8 +17,7 @@
    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"
@@ -31,6 +30,7 @@ struct smb_private {
        uint16_t fnum;
        struct smbcli_tree *tree;
        const char *server_name;
+       bool dead;
 };
 
 
@@ -39,7 +39,25 @@ struct smb_private {
 */
 static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
 {
-       c->transport.recv_data(c, NULL, status);
+       struct smb_private *smb = c->transport.private_data;
+
+       if (smb->dead) {
+               return;
+       }
+
+       smb->dead = true;
+
+       if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
+               status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
+               status = NT_STATUS_END_OF_FILE;
+       }
+
+       if (c->transport.recv_data) {
+               c->transport.recv_data(c, NULL, status);
+       }
 }
 
 
@@ -66,7 +84,7 @@ static void smb_read_callback(struct smbcli_request *req)
        NTSTATUS status;
 
        state = talloc_get_type(req->async.private, struct smb_read_state);
-       smb = talloc_get_type(state->c->transport.private, struct smb_private);
+       smb = talloc_get_type(state->c->transport.private_data, struct smb_private);
        io = state->io;
 
        status = smb_raw_read_recv(state->req, io);
@@ -123,7 +141,7 @@ static void smb_read_callback(struct smbcli_request *req)
 */
 static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb = c->transport.private_data;
        union smb_read *io;
        struct smb_read_state *state;
        struct smbcli_request *req;
@@ -179,6 +197,12 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO
 */
 static NTSTATUS send_read_request(struct dcerpc_connection *c)
 {
+       struct smb_private *smb = c->transport.private_data;
+
+       if (smb->dead) {
+               return NT_STATUS_CONNECTION_DISCONNECTED;
+       }
+
        return send_read_request_continue(c, NULL);
 }
 
@@ -225,7 +249,7 @@ static void smb_trans_callback(struct smbcli_request *req)
 */
 static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
 {
-        struct smb_private *smb = c->transport.private;
+        struct smb_private *smb = c->transport.private_data;
         struct smb_trans2 *trans;
         uint16_t setup[2];
        struct smb_trans_state *state;
@@ -288,10 +312,14 @@ static void smb_write_callback(struct smbcli_request *req)
 */
 static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, BOOL trigger_read)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb = c->transport.private_data;
        union smb_write io;
        struct smbcli_request *req;
 
+       if (smb->dead) {
+               return NT_STATUS_CONNECTION_DISCONNECTED;
+       }
+
        if (trigger_read) {
                return smb_send_trans_request(c, blob);
        }
@@ -326,14 +354,14 @@ static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, B
 /* 
    shutdown SMB pipe connection
 */
-static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
+static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb = c->transport.private_data;
        union smb_close io;
        struct smbcli_request *req;
 
        /* maybe we're still starting up */
-       if (!smb) return NT_STATUS_OK;
+       if (!smb) return status;
 
        io.close.level = RAW_CLOSE_CLOSE;
        io.close.in.file.fnum = smb->fnum;
@@ -346,7 +374,7 @@ static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
 
        talloc_free(smb);
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 /*
@@ -354,7 +382,7 @@ static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
 */
 static const char *smb_peer_name(struct dcerpc_connection *c)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb = c->transport.private_data;
        return smb->server_name;
 }
 
@@ -363,7 +391,7 @@ static const char *smb_peer_name(struct dcerpc_connection *c)
 */
 static const char *smb_target_hostname(struct dcerpc_connection *c)
 {
-       struct smb_private *smb = talloc_get_type(c->transport.private, struct smb_private);
+       struct smb_private *smb = talloc_get_type(c->transport.private_data, struct smb_private);
        return smb->tree->session->transport->socket->hostname;
 }
 
@@ -372,7 +400,7 @@ static const char *smb_target_hostname(struct dcerpc_connection *c)
 */
 static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb = c->transport.private_data;
 
        if (smb->tree->session->user_session_key.data) {
                *session_key = smb->tree->session->user_session_key;
@@ -384,34 +412,46 @@ static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_
 struct pipe_open_smb_state {
        union smb_open *open;
        struct dcerpc_connection *c;
-       struct smbcli_request *req;
        struct smbcli_tree *tree;
        struct composite_context *ctx;
 };
 
 static void pipe_open_recv(struct smbcli_request *req);
 
-struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_connection *c
+struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p
                                                    struct smbcli_tree *tree,
                                                    const char *pipe_name)
 {
        struct composite_context *ctx;
        struct pipe_open_smb_state *state;
+       struct smbcli_request *req;
+       struct dcerpc_connection *c = p->conn;
+
+       /* if we don't have a binding on this pipe yet, then create one */
+       if (p->binding == NULL) {
+               NTSTATUS status;
+               char *s = talloc_asprintf(p, "ncacn_np:%s", tree->session->transport->socket->hostname);
+               if (s == NULL) return NULL;
+               status = dcerpc_parse_binding(p, s, &p->binding);
+               talloc_free(s);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return NULL;
+               }
+       }
 
-       ctx = talloc_zero(NULL, struct composite_context);
-       if (ctx == NULL) goto failed;
-       ctx->state = COMPOSITE_STATE_IN_PROGRESS;
-       ctx->event_ctx = talloc_reference(c, c->event_ctx);
+       ctx = composite_create(c, c->event_ctx);
+       if (ctx == NULL) return NULL;
 
        state = talloc(ctx, struct pipe_open_smb_state);
-       if (state == NULL) goto failed;
+       if (composite_nomem(state, ctx)) return ctx;
+       ctx->private_data = state;
 
        state->c = c;
        state->tree = tree;
        state->ctx = ctx;
 
        state->open = talloc(state, union smb_open);
-       if (state->open == NULL) goto failed;
+       if (composite_nomem(state->open, ctx)) return ctx;
 
        state->open->ntcreatex.level = RAW_OPEN_NTCREATEX;
        state->open->ntcreatex.in.flags = 0;
@@ -441,38 +481,29 @@ struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_connection *c,
                (pipe_name[0] == '\\') ?
                talloc_strdup(state->open, pipe_name) :
                talloc_asprintf(state->open, "\\%s", pipe_name);
-       if (state->open->ntcreatex.in.fname == NULL) goto failed;
-
-       state->req = smb_raw_open_send(tree, state->open);
-       if (state->req == NULL) goto failed;
-
-       state->req->async.fn = pipe_open_recv;
-       state->req->async.private = state;
+       if (composite_nomem(state->open->ntcreatex.in.fname, ctx)) return ctx;
 
+       req = smb_raw_open_send(tree, state->open);
+       composite_continue_smb(ctx, req, pipe_open_recv, state);
        return ctx;
-
- failed:
-       talloc_free(ctx);
-       return NULL;
 }
 
 static void pipe_open_recv(struct smbcli_request *req)
 {
-       struct pipe_open_smb_state *state =
-               talloc_get_type(req->async.private,
-                               struct pipe_open_smb_state);
+       struct pipe_open_smb_state *state = talloc_get_type(req->async.private,
+                                           struct pipe_open_smb_state);
        struct composite_context *ctx = state->ctx;
        struct dcerpc_connection *c = state->c;
        struct smb_private *smb;
        
        ctx->status = smb_raw_open_recv(req, state, state->open);
-       if (!NT_STATUS_IS_OK(ctx->status)) goto done;
+       if (!composite_is_ok(ctx)) return;
 
        /*
          fill in the transport methods
        */
        c->transport.transport       = NCACN_NP;
-       c->transport.private         = NULL;
+       c->transport.private_data    = NULL;
        c->transport.shutdown_pipe   = smb_shutdown_pipe;
        c->transport.peer_name       = smb_peer_name;
        c->transport.target_hostname = smb_target_hostname;
@@ -485,32 +516,18 @@ static void pipe_open_recv(struct smbcli_request *req)
        c->security_state.session_key = smb_session_key;
 
        smb = talloc(c, struct smb_private);
-       if (smb == NULL) {
-               ctx->status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       if (composite_nomem(smb, ctx)) return;
 
        smb->fnum       = state->open->ntcreatex.out.file.fnum;
        smb->tree       = talloc_reference(smb, state->tree);
-       smb->server_name= strupper_talloc(
-               smb, state->tree->session->transport->called.name);
-       if (smb->server_name == NULL) {
-               ctx->status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-       c->transport.private = smb;
+       smb->server_name= strupper_talloc(smb,
+                         state->tree->session->transport->called.name);
+       if (composite_nomem(smb->server_name, ctx)) return;
+       smb->dead       = false;
 
-       ctx->status = NT_STATUS_OK;
-       ctx->state = COMPOSITE_STATE_DONE;
+       c->transport.private_data = smb;
 
- done:
-       if (!NT_STATUS_IS_OK(ctx->status)) {
-               ctx->state = COMPOSITE_STATE_ERROR;
-       }
-       if ((ctx->state >= COMPOSITE_STATE_DONE) &&
-           (ctx->async.fn != NULL)) {
-               ctx->async.fn(ctx);
-       }
+       composite_done(ctx);
 }
 
 NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
@@ -520,11 +537,11 @@ NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
        return status;
 }
 
-NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_connection *c,
+NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
                              struct smbcli_tree *tree,
                              const char *pipe_name)
 {
-       struct composite_context *ctx = dcerpc_pipe_open_smb_send(c, tree,
+       struct composite_context *ctx = dcerpc_pipe_open_smb_send(p, tree,
                                                                  pipe_name);
        return dcerpc_pipe_open_smb_recv(ctx);
 }
@@ -534,11 +551,27 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_connection *c,
 */
 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
 {
-       struct smb_private *smb = c->transport.private;
+       struct smb_private *smb;
 
-       if (c->transport.transport != NCACN_NP) {
-               return NULL;
-       }
+       if (c->transport.transport != NCACN_NP) return NULL;
+
+       smb = talloc_get_type(c->transport.private_data, struct smb_private);
+       if (!smb) return NULL;
 
        return smb->tree;
 }
+
+/*
+  return the SMB fnum used for a dcerpc over SMB pipe (hack for torture operations)
+*/
+uint16_t dcerpc_smb_fnum(struct dcerpc_connection *c)
+{
+       struct smb_private *smb;
+
+       if (c->transport.transport != NCACN_NP) return 0;
+
+       smb = talloc_get_type(c->transport.private_data, struct smb_private);
+       if (!smb) return 0;
+
+       return smb->fnum;
+}