s3-talloc Change TALLOC_ARRAY() to talloc_array()
[samba.git] / source3 / smbd / ipc.c
index 649ead468281e545656823f068025d053a5abbc9..b452000e13921ddbac3689d39d32cfaacf28d5b9 100644 (file)
    */
 
 #include "includes.h"
-
-extern int max_send;
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "smbprofile.h"
+#include "rpc_server/srv_pipe_hnd.h"
 
 #define NERR_notsupported 50
 
@@ -94,6 +96,8 @@ void send_trans_reply(connection_struct *conn,
 
        int ldata  = rdata  ? rdata_len : 0;
        int lparam = rparam ? rparam_len : 0;
+       struct smbd_server_connection *sconn = req->sconn;
+       int max_send = sconn->smb1.sessions.max_send;
 
        if (buffer_too_large)
                DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
@@ -134,8 +138,9 @@ void send_trans_reply(connection_struct *conn,
        }
 
        show_msg((char *)req->outbuf);
-       if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
-                         IS_CONN_ENCRYPTED(conn))) {
+       if (!srv_send_smb(sconn, (char *)req->outbuf,
+                         true, req->seqnum+1,
+                         IS_CONN_ENCRYPTED(conn), &req->pcd)) {
                exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
        }
 
@@ -171,6 +176,9 @@ void send_trans_reply(connection_struct *conn,
                                           rparam, tot_param_sent, this_lparam,
                                           rdata, tot_data_sent, this_ldata);
 
+               SSVAL(req->outbuf,smb_vwv0,lparam);
+               SSVAL(req->outbuf,smb_vwv1,ldata);
+
                SSVAL(req->outbuf,smb_vwv3,this_lparam);
                SSVAL(req->outbuf,smb_vwv4,
                      smb_offset(smb_buf(req->outbuf)+1,req->outbuf));
@@ -190,8 +198,9 @@ void send_trans_reply(connection_struct *conn,
                }
 
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
-                                 IS_CONN_ENCRYPTED(conn)))
+               if (!srv_send_smb(sconn, (char *)req->outbuf,
+                                 true, req->seqnum+1,
+                                 IS_CONN_ENCRYPTED(conn), &req->pcd))
                        exit_server_cleanly("send_trans_reply: srv_send_smb "
                                            "failed.");
 
@@ -205,34 +214,150 @@ void send_trans_reply(connection_struct *conn,
  Start the first part of an RPC reply which began with an SMBtrans request.
 ****************************************************************************/
 
-static void api_rpc_trans_reply(connection_struct *conn,
-                               struct smb_request *req,
-                               files_struct *fsp,
-                               int max_trans_reply)
+struct dcerpc_cmd_state {
+       struct fake_file_handle *handle;
+       uint8_t *data;
+       size_t num_data;
+       size_t max_read;
+};
+
+static void api_dcerpc_cmd_write_done(struct tevent_req *subreq);
+static void api_dcerpc_cmd_read_done(struct tevent_req *subreq);
+
+static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
+                          files_struct *fsp, uint8_t *data, size_t length,
+                          size_t max_read)
 {
-       bool is_data_outstanding;
-       uint8_t *rdata = SMB_MALLOC_ARRAY(uint8_t, max_trans_reply);
-       ssize_t data_len;
-       NTSTATUS status;
+       struct tevent_req *subreq;
+       struct dcerpc_cmd_state *state;
+       bool busy;
+
+       if (!fsp_is_np(fsp)) {
+               api_no_reply(conn, req);
+               return;
+       }
 
-       if(rdata == NULL) {
-               DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+       /*
+        * Trans requests are only allowed
+        * if no other Trans or Read is active
+        */
+       busy = np_read_in_progress(fsp->fake_file_handle);
+       if (busy) {
+               reply_nterror(req, NT_STATUS_PIPE_BUSY);
+               return;
+       }
+
+       state = talloc(req, struct dcerpc_cmd_state);
+       if (state == NULL) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
+       req->async_priv = state;
+
+       state->handle = fsp->fake_file_handle;
+
+       /*
+        * This memdup severely sucks. But doing it properly essentially means
+        * to rewrite lanman.c, something which I don't really want to do now.
+        */
+       state->data = (uint8_t *)talloc_memdup(state, data, length);
+       if (state->data == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+       state->num_data = length;
+       state->max_read = max_read;
+
+       subreq = np_write_send(state, server_event_context(), state->handle,
+                              state->data, length);
+       if (subreq == NULL) {
+               TALLOC_FREE(state);
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+       tevent_req_set_callback(subreq, api_dcerpc_cmd_write_done,
+                               talloc_move(conn, &req));
+}
+
+static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
+{
+       struct smb_request *req = tevent_req_callback_data(
+               subreq, struct smb_request);
+       struct dcerpc_cmd_state *state = talloc_get_type_abort(
+               req->async_priv, struct dcerpc_cmd_state);
+       NTSTATUS status;
+       ssize_t nwritten = -1;
+
+       status = np_write_recv(subreq, &nwritten);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status) || (nwritten != state->num_data)) {
+               DEBUG(10, ("Could not write to pipe: %s (%d/%d)\n",
+                          nt_errstr(status), (int)state->num_data,
+                          (int)nwritten));
+               reply_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
+               goto send;
+       }
+
+       state->data = talloc_realloc(state, state->data, uint8_t,
+                                          state->max_read);
+       if (state->data == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto send;
+       }
+
+       subreq = np_read_send(req->conn, server_event_context(),
+                             state->handle, state->data, state->max_read);
+       if (subreq == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto send;
+       }
+       tevent_req_set_callback(subreq, api_dcerpc_cmd_read_done, req);
+       return;
+
+ send:
+       if (!srv_send_smb(
+                   req->sconn, (char *)req->outbuf,
+                   true, req->seqnum+1,
+                   IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
+                   &req->pcd)) {
+               exit_server_cleanly("api_dcerpc_cmd_write_done: "
+                                   "srv_send_smb failed.");
+       }
+       TALLOC_FREE(req);
+}
+
+static void api_dcerpc_cmd_read_done(struct tevent_req *subreq)
+{
+       struct smb_request *req = tevent_req_callback_data(
+               subreq, struct smb_request);
+       struct dcerpc_cmd_state *state = talloc_get_type_abort(
+               req->async_priv, struct dcerpc_cmd_state);
+       NTSTATUS status;
+       ssize_t nread;
+       bool is_data_outstanding;
+
+       status = np_read_recv(subreq, &nread, &is_data_outstanding);
+       TALLOC_FREE(subreq);
 
-       status = np_read(fsp, rdata, max_trans_reply, &data_len,
-                        &is_data_outstanding);
        if (!NT_STATUS_IS_OK(status)) {
-               SAFE_FREE(rdata);
-               api_no_reply(conn,req);
+               DEBUG(10, ("Could not read from to pipe: %s\n",
+                          nt_errstr(status)));
+               reply_nterror(req, status);
+
+               if (!srv_send_smb(req->sconn, (char *)req->outbuf,
+                                 true, req->seqnum+1,
+                                 IS_CONN_ENCRYPTED(req->conn)
+                                 ||req->encrypted, &req->pcd)) {
+                       exit_server_cleanly("api_dcerpc_cmd_read_done: "
+                                           "srv_send_smb failed.");
+               }
+               TALLOC_FREE(req);
                return;
        }
 
-       send_trans_reply(conn, req, NULL, 0, (char *)rdata, data_len,
+       send_trans_reply(req->conn, req, NULL, 0, (char *)state->data, nread,
                         is_data_outstanding);
-       SAFE_FREE(rdata);
-       return;
+       TALLOC_FREE(req);
 }
 
 /****************************************************************************
@@ -305,7 +430,6 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
        struct files_struct *fsp;
        int pnum;
        int subcommand;
-       NTSTATUS status;
 
        DEBUG(5,("api_fd_reply\n"));
 
@@ -348,20 +472,15 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
        }
 
        DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n",
-                subcommand, fsp->fsp_name, pnum));
+                subcommand, fsp_str_dbg(fsp), pnum));
 
        DEBUG(10, ("api_fd_reply: p:%p max_trans_reply: %d\n", fsp, mdrcnt));
 
        switch (subcommand) {
        case TRANSACT_DCERPCCMD: {
                /* dce/rpc command */
-               ssize_t nwritten;
-               status = np_write(fsp, data, tdscnt, &nwritten);
-               if (!NT_STATUS_IS_OK(status)) {
-                       api_no_reply(conn, req);
-                       return;
-               }
-               api_rpc_trans_reply(conn, req, fsp, mdrcnt);
+               api_dcerpc_cmd(conn, req, fsp, (uint8_t *)data, tdscnt,
+                              mdrcnt);
                break;
        }
        case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
@@ -623,7 +742,7 @@ void reply_trans(struct smb_request *req)
                        goto bad_param;
                }
 
-               if((state->setup = TALLOC_ARRAY(
+               if((state->setup = talloc_array(
                            state, uint16, state->setup_count)) == NULL) {
                        DEBUG(0,("reply_trans: setup malloc fail for %u "
                                 "bytes !\n", (unsigned int)
@@ -655,6 +774,8 @@ void reply_trans(struct smb_request *req)
                return;
        }
 
+       talloc_steal(talloc_tos(), state);
+
        handle_trans(conn, req, state);
 
        SAFE_FREE(state->data);
@@ -687,7 +808,7 @@ void reply_transs(struct smb_request *req)
 
        START_PROFILE(SMBtranss);
 
-       show_msg((char *)req->inbuf);
+       show_msg((const char *)req->inbuf);
 
        if (req->wct < 8) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -753,6 +874,8 @@ void reply_transs(struct smb_request *req)
                return;
        }
 
+       talloc_steal(talloc_tos(), state);
+
        handle_trans(conn, req, state);
 
        DLIST_REMOVE(conn->pending_trans, state);