s3-rpc_server: Convert rpc_connect_spoolss_pipe into a generic interface.
[kamenim/samba.git] / source3 / smbd / reply.c
index f909fd696d2f9dd0ed544c946c410017067ce4f4..4ace452ed92a630d5fe52f7919e932805754745d 100644 (file)
@@ -27,6 +27,7 @@
 #include "includes.h"
 #include "printing.h"
 #include "smbd/globals.h"
+#include "fake_file.h"
 #include "../librpc/gen_ndr/cli_spoolss.h"
 #include "rpc_client/cli_spoolss.h"
 #include "rpc_client/init_spoolss.h"
@@ -468,7 +469,7 @@ static bool netbios_session_retarget(struct smbd_server_connection *sconn,
        *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
        *(uint16_t *)(outbuf+8) = htons(retarget_port);
 
-       if (!srv_send_smb(sconn->sock, (char *)outbuf, false, 0, false,
+       if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
                          NULL)) {
                exit_server_cleanly("netbios_session_regarget: srv_send_smb "
                                    "failed.");
@@ -527,6 +528,15 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf)
                        exit_server_cleanly("retargeted client");
                }
 
+               /*
+                * Windows NT/2k uses "*SMBSERVER" and XP uses
+                * "*SMBSERV" arrggg!!!
+                */
+               if (strequal(name1, "*SMBSERVER     ")
+                   || strequal(name1, "*SMBSERV       "))  {
+                       fstrcpy(name1, sconn->client_id.addr);
+               }
+
                set_local_machine_name(name1, True);
                set_remote_machine_name(name2, True);
 
@@ -548,7 +558,7 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf)
                        add_session_user(sconn, get_remote_machine_name());
                }
 
-               reload_services(sconn->msg_ctx, True);
+               reload_services(sconn->msg_ctx, sconn->sock, True);
                reopen_logs();
 
                sconn->nbt.got_session = true;
@@ -574,7 +584,7 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf)
        DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
                    msg_type, msg_flags));
 
-       srv_send_smb(sconn->sock, outbuf, false, 0, false, NULL);
+       srv_send_smb(sconn, outbuf, false, 0, false, NULL);
        return;
 }
 
@@ -2810,7 +2820,18 @@ static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
                        memset(buf + ret, '\0', cur_read - ret);
                }
 
-               if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+               if (write_data(fsp->conn->sconn->sock, buf, cur_read)
+                   != cur_read) {
+                       char addr[INET6_ADDRSTRLEN];
+                       /*
+                        * Try and give an error message saying what
+                        * client failed.
+                        */
+                       DEBUG(0, ("write_data failed for client %s. "
+                                 "Error %s\n",
+                                 get_peer_addr(fsp->conn->sconn->sock, addr,
+                                               sizeof(addr)),
+                                 strerror(errno)));
                        SAFE_FREE(buf);
                        return -1;
                }
@@ -2871,9 +2892,21 @@ static void sendfile_short_send(files_struct *fsp,
                        size_t to_write;
 
                        to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
-                       if (write_data(smbd_server_fd(), buf, to_write) != to_write) {
+                       if (write_data(fsp->conn->sconn->sock, buf, to_write)
+                           != to_write) {
+                               char addr[INET6_ADDRSTRLEN];
+                               /*
+                                * Try and give an error message saying what
+                                * client failed.
+                                */
+                               DEBUG(0, ("write_data failed for client %s. "
+                                         "Error %s\n",
+                                         get_peer_addr(
+                                                 fsp->conn->sconn->sock, addr,
+                                                 sizeof(addr)),
+                                         strerror(errno)));
                                exit_server_cleanly("sendfile_short_send: "
-                                       "write_data failed");
+                                                   "write_data failed");
                        }
                        nread += to_write;
                }
@@ -2893,7 +2926,17 @@ static void reply_readbraw_error(struct smbd_server_connection *sconn)
        SIVAL(header,0,0);
 
        smbd_lock_socket(sconn);
-       if (write_data(smbd_server_fd(),header,4) != 4) {
+       if (write_data(sconn->sock,header,4) != 4) {
+               char addr[INET6_ADDRSTRLEN];
+               /*
+                * Try and give an error message saying what
+                * client failed.
+                */
+               DEBUG(0, ("write_data failed for client %s. "
+                         "Error %s\n",
+                         get_peer_addr(sconn->sock, addr, sizeof(addr)),
+                         strerror(errno)));
+
                fail_readraw();
        }
        smbd_unlock_socket(sconn);
@@ -2932,8 +2975,10 @@ static void send_file_readbraw(connection_struct *conn,
                _smb_setlen(header,nread);
                header_blob = data_blob_const(header, 4);
 
-               if ((sendfile_read = SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
-                               &header_blob, startpos, nread)) == -1) {
+               sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
+                                                &header_blob, startpos,
+                                                nread);
+               if (sendfile_read == -1) {
                        /* Returning ENOSYS means no data at all was sent.
                         * Do this as a normal read. */
                        if (errno == ENOSYS) {
@@ -3009,8 +3054,20 @@ normal_readbraw:
        }
 
        _smb_setlen(outbuf,ret);
-       if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
+       if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
+               char addr[INET6_ADDRSTRLEN];
+               /*
+                * Try and give an error message saying what
+                * client failed.
+                */
+               DEBUG(0, ("write_data failed for client %s. "
+                         "Error %s\n",
+                         get_peer_addr(fsp->conn->sconn->sock, addr,
+                                       sizeof(addr)),
+                         strerror(errno)));
+
                fail_readraw();
+       }
 
        TALLOC_FREE(outbuf);
 }
@@ -3475,7 +3532,9 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                construct_reply_common_req(req, (char *)headerbuf);
                setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
 
-               if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
+               nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
+                                        startpos, smb_maxcnt);
+               if (nread == -1) {
                        /* Returning ENOSYS means no data at all was sent.
                           Do this as a normal read. */
                        if (errno == ENOSYS) {
@@ -3550,8 +3609,20 @@ normal_read:
                setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
 
                /* Send out the header. */
-               if (write_data(smbd_server_fd(), (char *)headerbuf,
+               if (write_data(req->sconn->sock, (char *)headerbuf,
                               sizeof(headerbuf)) != sizeof(headerbuf)) {
+
+                       char addr[INET6_ADDRSTRLEN];
+                       /*
+                        * Try and give an error message saying what
+                        * client failed.
+                        */
+                       DEBUG(0, ("write_data failed for client %s. "
+                                 "Error %s\n",
+                                 get_peer_addr(req->sconn->sock, addr,
+                                               sizeof(addr)),
+                                 strerror(errno)));
+
                        DEBUG(0,("send_file_readX: write_data failed for file "
                                 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
                                 strerror(errno)));
@@ -3735,6 +3806,43 @@ void error_to_writebrawerr(struct smb_request *req)
        TALLOC_FREE(old_outbuf);
 }
 
+/****************************************************************************
+ Read 4 bytes of a smb packet and return the smb length of the packet.
+ Store the result in the buffer. This version of the function will
+ never return a session keepalive (length of zero).
+ Timeout is in milliseconds.
+****************************************************************************/
+
+static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
+                               size_t *len)
+{
+       uint8_t msgtype = SMBkeepalive;
+
+       while (msgtype == SMBkeepalive) {
+               NTSTATUS status;
+
+               status = read_smb_length_return_keepalive(fd, inbuf, timeout,
+                                                         len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       char addr[INET6_ADDRSTRLEN];
+                       /* Try and give an error message
+                        * saying what client failed. */
+                       DEBUG(0, ("read_fd_with_timeout failed for "
+                                 "client %s read error = %s.\n",
+                                 get_peer_addr(fd,addr,sizeof(addr)),
+                                 nt_errstr(status)));
+                       return status;
+               }
+
+               msgtype = CVAL(inbuf, 0);
+       }
+
+       DEBUG(10,("read_smb_length: got smb length of %lu\n",
+                 (unsigned long)len));
+
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Reply to a writebraw (core+ or LANMAN1.0 protocol).
 ****************************************************************************/
@@ -3868,7 +3976,7 @@ void reply_writebraw(struct smb_request *req)
        SCVAL(buf,smb_com,SMBwritebraw);
        SSVALS(buf,smb_vwv0,0xFFFF);
        show_msg(buf);
-       if (!srv_send_smb(smbd_server_fd(),
+       if (!srv_send_smb(req->sconn,
                          buf,
                          false, 0, /* no signing */
                          IS_CONN_ENCRYPTED(conn),
@@ -3878,7 +3986,7 @@ void reply_writebraw(struct smb_request *req)
        }
 
        /* Now read the raw data into the buffer and write it */
-       status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
+       status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
                                 &numtowrite);
        if (!NT_STATUS_IS_OK(status)) {
                exit_server_cleanly("secondary writebraw failed");
@@ -3902,12 +4010,17 @@ void reply_writebraw(struct smb_request *req)
                                (int)tcount,(int)nwritten,(int)numtowrite));
                }
 
-               status = read_data(smbd_server_fd(), buf+4, numtowrite);
+               status = read_data(req->sconn->sock, buf+4, numtowrite);
 
                if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0,("reply_writebraw: Oversize secondary write "
-                                "raw read failed (%s). Terminating\n",
-                                nt_errstr(status)));
+                       char addr[INET6_ADDRSTRLEN];
+                       /* Try and give an error message
+                        * saying what client failed. */
+                       DEBUG(0, ("reply_writebraw: Oversize secondary write "
+                                 "raw read failed (%s) for client %s. "
+                                 "Terminating\n", nt_errstr(status),
+                                 get_peer_addr(req->sconn->sock, addr,
+                                               sizeof(addr))));
                        exit_server_cleanly("secondary writebraw failed");
                }
 
@@ -3962,7 +4075,7 @@ void reply_writebraw(struct smb_request *req)
                 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
                 * JRA.
                 */
-               if (!send_keepalive(smbd_server_fd())) {
+               if (!send_keepalive(req->sconn->sock)) {
                        exit_server_cleanly("reply_writebraw: send of "
                                "keepalive failed");
                }
@@ -5010,7 +5123,7 @@ void reply_echo(struct smb_request *req)
                SSVAL(req->outbuf,smb_vwv0,seq_num);
 
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(smbd_server_fd(),
+               if (!srv_send_smb(req->sconn,
                                (char *)req->outbuf,
                                true, req->seqnum+1,
                                IS_CONN_ENCRYPTED(conn)||req->encrypted,
@@ -5181,7 +5294,12 @@ void reply_printqueue(struct smb_request *req)
 
                ZERO_STRUCT(handle);
 
-               status = rpc_connect_spoolss_pipe(conn, &cli);
+               status = rpc_pipe_open_interface(conn,
+                                                &ndr_table_spoolss.syntax_id,
+                                                conn->server_info,
+                                                &conn->sconn->client_id,
+                                                conn->sconn->msg_ctx,
+                                                &cli);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("reply_printqueue: "
                                  "could not connect to spoolss: %s\n",