libndr: Avoid assigning duplicate versions to symbols
[amitay/samba.git] / source3 / smbd / ipc.c
index a93fdd5ae0edbaa8bbbbc65b3414a7e8e28d9148..f1c8ea0c2ed43d3e3e4740a10ce36dd458f04bb0 100644 (file)
    */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
+#include "smbprofile.h"
+#include "rpc_server/srv_pipe_hnd.h"
 
 #define NERR_notsupported 50
 
@@ -76,6 +79,17 @@ static void copy_trans_params_and_data(char *outbuf, int align,
                memcpy(copy_into, &rdata[data_offset], data_len);
 }
 
+NTSTATUS nt_status_np_pipe(NTSTATUS status)
+{
+       if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+               status = NT_STATUS_PIPE_DISCONNECTED;
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+               status = NT_STATUS_PIPE_BROKEN;
+       }
+
+       return status;
+}
+
 /****************************************************************************
  Send a trans reply.
  ****************************************************************************/
@@ -93,14 +107,16 @@ void send_trans_reply(connection_struct *conn,
 
        int ldata  = rdata  ? rdata_len : 0;
        int lparam = rparam ? rparam_len : 0;
-       struct smbd_server_connection *sconn = smbd_server_conn;
-       int max_send = sconn->smb1.sessions.max_send;
+       struct smbXsrv_connection *xconn = req->xconn;
+       int max_send = xconn->smb1.sessions.max_send;
+       /* HACK: make sure we send at least 128 byte in one go */
+       int hdr_overhead = SMB_BUFFER_SIZE_MIN - 128;
 
        if (buffer_too_large)
                DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
 
-       this_lparam = MIN(lparam,max_send - 500); /* hack */
-       this_ldata  = MIN(ldata,max_send - (500+this_lparam));
+       this_lparam = MIN(lparam,max_send - hdr_overhead);
+       this_ldata  = MIN(ldata,max_send - (hdr_overhead+this_lparam));
 
        align = ((this_lparam)%4);
 
@@ -135,7 +151,7 @@ void send_trans_reply(connection_struct *conn,
        }
 
        show_msg((char *)req->outbuf);
-       if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+       if (!srv_send_smb(xconn, (char *)req->outbuf,
                          true, req->seqnum+1,
                          IS_CONN_ENCRYPTED(conn), &req->pcd)) {
                exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
@@ -149,9 +165,9 @@ void send_trans_reply(connection_struct *conn,
        while (tot_data_sent < ldata || tot_param_sent < lparam)
        {
                this_lparam = MIN(lparam-tot_param_sent,
-                                 max_send - 500); /* hack */
+                                 max_send - hdr_overhead);
                this_ldata  = MIN(ldata -tot_data_sent,
-                                 max_send - (500+this_lparam));
+                                 max_send - (hdr_overhead+this_lparam));
 
                if(this_lparam < 0)
                        this_lparam = 0;
@@ -173,6 +189,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));
@@ -192,7 +211,7 @@ void send_trans_reply(connection_struct *conn,
                }
 
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+               if (!srv_send_smb(xconn, (char *)req->outbuf,
                                  true, req->seqnum+1,
                                  IS_CONN_ENCRYPTED(conn), &req->pcd))
                        exit_server_cleanly("send_trans_reply: srv_send_smb "
@@ -224,12 +243,23 @@ static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
 {
        struct tevent_req *subreq;
        struct dcerpc_cmd_state *state;
+       bool busy;
 
        if (!fsp_is_np(fsp)) {
                api_no_reply(conn, req);
                return;
        }
 
+       /*
+        * 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);
@@ -251,7 +281,7 @@ static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
        state->num_data = length;
        state->max_read = max_read;
 
-       subreq = np_write_send(state, smbd_event_context(), state->handle,
+       subreq = np_write_send(state, req->sconn->ev_ctx, state->handle,
                               state->data, length);
        if (subreq == NULL) {
                TALLOC_FREE(state);
@@ -273,22 +303,34 @@ static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
 
        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);
+       if (!NT_STATUS_IS_OK(status)) {
+               NTSTATUS old = status;
+               status = nt_status_np_pipe(old);
+
+               DEBUG(10, ("Could not write to pipe: %s%s%s\n",
+                          nt_errstr(old),
+                          NT_STATUS_EQUAL(old, status)?"":" => ",
+                          NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
+               reply_nterror(req, status);
+               goto send;
+       }
+       if (nwritten != state->num_data) {
+               status = NT_STATUS_PIPE_NOT_AVAILABLE;
+               DEBUG(10, ("Could not write to pipe: (%d/%d) => %s\n",
+                          (int)state->num_data,
+                          (int)nwritten, nt_errstr(status)));
+               reply_nterror(req, status);
                goto send;
        }
 
-       state->data = TALLOC_REALLOC_ARRAY(state, state->data, uint8_t,
+       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, smbd_event_context(),
+       subreq = np_read_send(state, req->sconn->ev_ctx,
                              state->handle, state->data, state->max_read);
        if (subreq == NULL) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
@@ -299,11 +341,12 @@ static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
 
  send:
        if (!srv_send_smb(
-                   smbd_server_fd(), (char *)req->outbuf,
+                   req->xconn, (char *)req->outbuf,
                    true, req->seqnum+1,
                    IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
                    &req->pcd)) {
-               exit_server_cleanly("construct_reply: srv_send_smb failed.");
+               exit_server_cleanly("api_dcerpc_cmd_write_done: "
+                                   "srv_send_smb failed.");
        }
        TALLOC_FREE(req);
 }
@@ -322,16 +365,21 @@ static void api_dcerpc_cmd_read_done(struct tevent_req *subreq)
        TALLOC_FREE(subreq);
 
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(10, ("Could not read from to pipe: %s\n",
-                          nt_errstr(status)));
+               NTSTATUS old = status;
+               status = nt_status_np_pipe(old);
+
+               DEBUG(10, ("Could not read from to pipe: %s%s%s\n",
+                          nt_errstr(old),
+                          NT_STATUS_EQUAL(old, status)?"":" => ",
+                          NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
                reply_nterror(req, status);
 
-               if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+               if (!srv_send_smb(req->xconn, (char *)req->outbuf,
                                  true, req->seqnum+1,
                                  IS_CONN_ENCRYPTED(req->conn)
                                  ||req->encrypted, &req->pcd)) {
-                       exit_server_cleanly("construct_reply: srv_send_smb "
-                                           "failed.");
+                       exit_server_cleanly("api_dcerpc_cmd_read_done: "
+                                           "srv_send_smb failed.");
                }
                TALLOC_FREE(req);
                return;
@@ -403,9 +451,9 @@ static void api_no_reply(connection_struct *conn, struct smb_request *req)
  Handle remote api calls delivered to a named pipe already opened.
  ****************************************************************************/
 
-static void api_fd_reply(connection_struct *conn, uint16 vuid,
+static void api_fd_reply(connection_struct *conn, uint64_t vuid,
                         struct smb_request *req,
-                        uint16 *setup, uint8_t *data, char *params,
+                        uint16_t *setup, uint8_t *data, char *params,
                         int suwcnt, int tdscnt, int tpscnt,
                         int mdrcnt, int mprcnt)
 {
@@ -447,14 +495,15 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
        }
 
        if (vuid != fsp->vuid) {
-               DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %d, "
-                         "expected %d\n", pnum, vuid, fsp->vuid));
+               DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %llu, "
+                         "expected %llu\n", pnum, (unsigned long long)vuid,
+                         (unsigned long long)fsp->vuid));
                reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                return;
        }
 
        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));
 
@@ -483,9 +532,9 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
  Handle named pipe commands.
 ****************************************************************************/
 
-static void named_pipe(connection_struct *conn, uint16 vuid,
+static void named_pipe(connection_struct *conn, uint64_t vuid,
                       struct smb_request *req,
-                      const char *name, uint16 *setup,
+                      const char *name, uint16_t *setup,
                       char *data, char *params,
                       int suwcnt, int tdscnt,int tpscnt,
                       int msrcnt, int mdrcnt, int mprcnt)
@@ -584,8 +633,30 @@ static void handle_trans(connection_struct *conn, struct smb_request *req,
                   state->max_param_return);
 
        if (state->close_on_completion) {
-               close_cnum(conn,state->vuid);
+               struct smbXsrv_tcon *tcon;
+               NTSTATUS status;
+
+               tcon = conn->tcon;
                req->conn = NULL;
+               conn = NULL;
+
+               /*
+                * TODO: cancel all outstanding requests on the tcon
+                */
+               status = smbXsrv_tcon_disconnect(tcon, state->vuid);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("handle_trans: "
+                                 "smbXsrv_tcon_disconnect() failed: %s\n",
+                                 nt_errstr(status)));
+                       /*
+                        * If we hit this case, there is something completely
+                        * wrong, so we better disconnect the transport connection.
+                        */
+                       exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
+                       return;
+               }
+
+               TALLOC_FREE(tcon);
        }
 
        return;
@@ -627,7 +698,7 @@ void reply_trans(struct smb_request *req)
                return;
        }
 
-       if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
+       if ((state = talloc(conn, struct trans_state)) == NULL) {
                DEBUG(0, ("talloc failed\n"));
                reply_nterror(req, NT_STATUS_NO_MEMORY);
                END_PROFILE(SMBtrans);
@@ -724,11 +795,11 @@ void reply_trans(struct smb_request *req)
                        goto bad_param;
                }
 
-               if((state->setup = TALLOC_ARRAY(
-                           state, uint16, state->setup_count)) == NULL) {
+               if((state->setup = talloc_array(
+                           state, uint16_t, state->setup_count)) == NULL) {
                        DEBUG(0,("reply_trans: setup malloc fail for %u "
                                 "bytes !\n", (unsigned int)
-                                (state->setup_count * sizeof(uint16))));
+                                (state->setup_count * sizeof(uint16_t))));
                        SAFE_FREE(state->data);
                        SAFE_FREE(state->param);
                        TALLOC_FREE(state);
@@ -790,7 +861,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);