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/>.
*/
/*
This file handles reply_ calls on named pipes that the server
#define MAX_PIPE_NAME_LEN 24
-/* PIPE/<name>/<pid>/<pnum> */
-#define PIPEDB_KEY_FORMAT "PIPE/%s/%u/%d"
-
-struct pipe_dbrec {
- struct server_id pid;
- int pnum;
- uid_t uid;
+NTSTATUS open_np_file(struct smb_request *smb_req, const char *name,
+ struct files_struct **pfsp)
+{
+ struct connection_struct *conn = smb_req->conn;
+ struct files_struct *fsp;
+ NTSTATUS status;
+
+ status = file_new(smb_req, conn, &fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("file_new failed: %s\n", nt_errstr(status)));
+ return status;
+ }
- char name[MAX_PIPE_NAME_LEN];
- fstring user;
-};
+ fsp->conn = conn;
+ fsp->fh->fd = -1;
+ fsp->vuid = smb_req->vuid;
+ fsp->can_lock = false;
+ fsp->access_mask = FILE_READ_DATA | FILE_WRITE_DATA;
+ string_set(&fsp->fsp_name, name);
+
+ status = np_open(NULL, name, conn->client_address,
+ conn->server_info, &fsp->fake_file_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("np_open(%s) returned %s\n", name,
+ nt_errstr(status)));
+ file_free(smb_req, fsp);
+ return status;
+ }
+ *pfsp = fsp;
-extern struct pipe_id_info pipe_names[];
+ return NT_STATUS_OK;
+}
/****************************************************************************
Reply to an open and X on a named pipe.
wrinkles to handle pipes.
****************************************************************************/
-int reply_open_pipe_and_X(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
{
- pstring fname;
- pstring pipe_name;
- uint16 vuid = SVAL(inbuf, smb_uid);
- smb_np_struct *p;
- int size=0,fmode=0,mtime=0,rmode=0;
- int i;
+ const char *fname = NULL;
+ char *pipe_name = NULL;
+ files_struct *fsp;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS status;
/* XXXX we need to handle passed times, sattr and flags */
- srvstr_pull_buf(inbuf, pipe_name, smb_buf(inbuf), sizeof(pipe_name), STR_TERMINATE);
+ srvstr_pull_req_talloc(ctx, req, &pipe_name, req->buf, STR_TERMINATE);
+ if (!pipe_name) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
/* If the name doesn't start \PIPE\ then this is directed */
/* at a mailslot or something we really, really don't understand, */
/* not just something we really don't understand. */
if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) {
- return(ERROR_DOS(ERRSRV,ERRaccess));
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
}
DEBUG(4,("Opening pipe %s.\n", pipe_name));
- /* See if it is one we want to handle. */
- for( i = 0; pipe_names[i].client_pipe ; i++ ) {
- if( strequal(pipe_name,pipe_names[i].client_pipe)) {
- break;
- }
- }
-
- if (pipe_names[i].client_pipe == NULL) {
- return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
- }
-
/* Strip \PIPE\ off the name. */
- pstrcpy(fname, pipe_name + PIPELEN);
+ fname = pipe_name + PIPELEN;
#if 0
/*
* Hack for NT printers... JRA.
*/
- if(should_fail_next_srvsvc_open(fname))
- return(ERROR(ERRSRV,ERRaccess));
+ if(should_fail_next_srvsvc_open(fname)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
#endif
- /* Known pipes arrive with DIR attribs. Remove it so a regular file */
- /* can be opened and add it in after the open. */
- DEBUG(3,("Known pipe %s opening.\n",fname));
-
- p = open_rpc_pipe_p(fname, conn, vuid);
- if (!p) {
- return(ERROR_DOS(ERRSRV,ERRnofids));
+ status = open_np_file(req, fname, &fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
+ reply_nterror(req, status);
+ return;
}
/* Prepare the reply */
- set_message(inbuf,outbuf,15,0,True);
+ reply_outbuf(req, 15, 0);
/* Mark the opened file as an existing named pipe in message mode. */
- SSVAL(outbuf,smb_vwv9,2);
- SSVAL(outbuf,smb_vwv10,0xc700);
-
- if (rmode == 2) {
- DEBUG(4,("Resetting open result to open from create.\n"));
- rmode = 1;
- }
-
- SSVAL(outbuf,smb_vwv2, p->pnum);
- SSVAL(outbuf,smb_vwv3,fmode);
- srv_put_dos_date3(outbuf,smb_vwv4,mtime);
- SIVAL(outbuf,smb_vwv6,size);
- SSVAL(outbuf,smb_vwv8,rmode);
- SSVAL(outbuf,smb_vwv11,0x0001);
-
- return chain_reply(inbuf,outbuf,length,bufsize);
+ SSVAL(req->outbuf,smb_vwv9,2);
+ SSVAL(req->outbuf,smb_vwv10,0xc700);
+
+ SSVAL(req->outbuf, smb_vwv2, fsp->fnum);
+ SSVAL(req->outbuf, smb_vwv3, 0); /* fmode */
+ srv_put_dos_date3((char *)req->outbuf, smb_vwv4, 0); /* mtime */
+ SIVAL(req->outbuf, smb_vwv6, 0); /* size */
+ SSVAL(req->outbuf, smb_vwv8, 0); /* rmode */
+ SSVAL(req->outbuf, smb_vwv11, 0x0001);
+
+ chain_reply(req);
+ return;
}
/****************************************************************************
Reply to a write on a pipe.
****************************************************************************/
-int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize)
+struct pipe_write_state {
+ size_t numtowrite;
+};
+
+static void pipe_write_done(struct tevent_req *subreq);
+
+void reply_pipe_write(struct smb_request *req)
{
- smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
- uint16 vuid = SVAL(inbuf,smb_uid);
- size_t numtowrite = SVAL(inbuf,smb_vwv1);
- int nwritten;
- int outsize;
- char *data;
-
- if (!p) {
- return(ERROR_DOS(ERRDOS,ERRbadfid));
+ files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
+ const uint8_t *data;
+ struct pipe_write_state *state;
+ struct tevent_req *subreq;
+
+ if (!fsp_is_np(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ if (fsp->vuid != req->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
}
- if (p->vuid != vuid) {
- return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ state = talloc(req, struct pipe_write_state);
+ if (state == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
+ req->async_priv = state;
+
+ state->numtowrite = SVAL(req->vwv+1, 0);
- data = smb_buf(inbuf) + 3;
+ data = req->buf + 3;
- if (numtowrite == 0) {
- nwritten = 0;
- } else {
- nwritten = write_to_pipe(p, data, numtowrite);
+ DEBUG(6, ("reply_pipe_write: %x name: %s len: %d\n", (int)fsp->fnum,
+ fsp->fsp_name, (int)state->numtowrite));
+
+ subreq = np_write_send(state, smbd_event_context(),
+ fsp->fake_file_handle, data, state->numtowrite);
+ if (subreq == NULL) {
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
+ tevent_req_set_callback(subreq, pipe_write_done,
+ talloc_move(req->conn, &req));
+}
- if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
- return (UNIXERROR(ERRDOS,ERRnoaccess));
+static void pipe_write_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = tevent_req_callback_data(
+ subreq, struct smb_request);
+ struct pipe_write_state *state = talloc_get_type_abort(
+ req->async_priv, struct pipe_write_state);
+ NTSTATUS status;
+ ssize_t nwritten = -1;
+
+ status = np_write_recv(subreq, &nwritten);
+ TALLOC_FREE(subreq);
+ if ((nwritten == 0 && state->numtowrite != 0) || (nwritten < 0)) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ goto send;
}
-
- outsize = set_message(inbuf,outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
-
- DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
+ reply_outbuf(req, 1, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,nwritten);
- return(outsize);
+ DEBUG(3,("write-IPC nwritten=%d\n", (int)nwritten));
+
+ send:
+ if (!srv_send_smb(smbd_server_fd(), (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.");
+ }
+ TALLOC_FREE(req);
}
/****************************************************************************
wrinkles to handle pipes.
****************************************************************************/
-int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+struct pipe_write_andx_state {
+ bool pipe_start_message_raw;
+ size_t numtowrite;
+};
+
+static void pipe_write_andx_done(struct tevent_req *subreq);
+
+void reply_pipe_write_and_X(struct smb_request *req)
{
- smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
- uint16 vuid = SVAL(inbuf,smb_uid);
- size_t numtowrite = SVAL(inbuf,smb_vwv10);
- int nwritten = -1;
- int smb_doff = SVAL(inbuf, smb_vwv11);
- BOOL pipe_start_message_raw = ((SVAL(inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) ==
- (PIPE_START_MESSAGE|PIPE_RAW_MODE));
- char *data;
-
- if (!p) {
- return(ERROR_DOS(ERRDOS,ERRbadfid));
+ files_struct *fsp = file_fsp(req, SVAL(req->vwv+2, 0));
+ int smb_doff = SVAL(req->vwv+11, 0);
+ uint8_t *data;
+ struct pipe_write_andx_state *state;
+ struct tevent_req *subreq;
+
+ if (!fsp_is_np(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
}
- if (p->vuid != vuid) {
- return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+ if (fsp->vuid != req->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
}
- data = smb_base(inbuf) + smb_doff;
-
- if (numtowrite == 0) {
- nwritten = 0;
- } else {
- if(pipe_start_message_raw) {
- /*
- * For the start of a message in named pipe byte mode,
- * the first two bytes are a length-of-pdu field. Ignore
- * them (we don't trust the client). JRA.
- */
- if(numtowrite < 2) {
- DEBUG(0,("reply_pipe_write_and_X: start of message set and not enough data sent.(%u)\n",
- (unsigned int)numtowrite ));
- return (UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- data += 2;
- numtowrite -= 2;
- }
- nwritten = write_to_pipe(p, data, numtowrite);
+ state = talloc(req, struct pipe_write_andx_state);
+ if (state == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
+ req->async_priv = state;
+
+ state->numtowrite = SVAL(req->vwv+10, 0);
+ state->pipe_start_message_raw =
+ ((SVAL(req->vwv+7, 0) & (PIPE_START_MESSAGE|PIPE_RAW_MODE))
+ == (PIPE_START_MESSAGE|PIPE_RAW_MODE));
+
+ DEBUG(6, ("reply_pipe_write_and_X: %x name: %s len: %d\n",
+ (int)fsp->fnum, fsp->fsp_name, (int)state->numtowrite));
+
+ data = (uint8_t *)smb_base(req->inbuf) + smb_doff;
+
+ if (state->pipe_start_message_raw) {
+ /*
+ * For the start of a message in named pipe byte mode,
+ * the first two bytes are a length-of-pdu field. Ignore
+ * them (we don't trust the client). JRA.
+ */
+ if (state->numtowrite < 2) {
+ DEBUG(0,("reply_pipe_write_and_X: start of message "
+ "set and not enough data sent.(%u)\n",
+ (unsigned int)state->numtowrite ));
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
- if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
- return (UNIXERROR(ERRDOS,ERRnoaccess));
+ data += 2;
+ state->numtowrite -= 2;
}
-
- set_message(inbuf,outbuf,6,0,True);
- nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten);
- SSVAL(outbuf,smb_vwv2,nwritten);
-
- DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
+ subreq = np_write_send(state, smbd_event_context(),
+ fsp->fake_file_handle, data, state->numtowrite);
+ if (subreq == NULL) {
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ tevent_req_set_callback(subreq, pipe_write_andx_done,
+ talloc_move(req->conn, &req));
+}
- return chain_reply(inbuf,outbuf,length,bufsize);
+static void pipe_write_andx_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = tevent_req_callback_data(
+ subreq, struct smb_request);
+ struct pipe_write_andx_state *state = talloc_get_type_abort(
+ req->async_priv, struct pipe_write_andx_state);
+ NTSTATUS status;
+ ssize_t nwritten = -1;
+
+ status = np_write_recv(subreq, &nwritten);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status) || (nwritten != state->numtowrite)) {
+ reply_unixerror(req, ERRDOS,ERRnoaccess);
+ goto done;
+ }
+
+ reply_outbuf(req, 6, 0);
+
+ nwritten = (state->pipe_start_message_raw ? nwritten + 2 : nwritten);
+ SSVAL(req->outbuf,smb_vwv2,nwritten);
+
+ DEBUG(3,("writeX-IPC nwritten=%d\n", (int)nwritten));
+
+ done:
+ chain_reply(req);
}
/****************************************************************************
wrinkles to handle pipes.
****************************************************************************/
-int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+struct pipe_read_andx_state {
+ uint8_t *outbuf;
+ int smb_mincnt;
+ int smb_maxcnt;
+};
+
+static void pipe_read_andx_done(struct tevent_req *subreq);
+
+void reply_pipe_read_and_X(struct smb_request *req)
{
- smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
- int smb_maxcnt = SVAL(inbuf,smb_vwv5);
- int smb_mincnt = SVAL(inbuf,smb_vwv6);
- int nread = -1;
- char *data;
- BOOL unused;
+ files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
+ uint8_t *data;
+ struct pipe_read_andx_state *state;
+ struct tevent_req *subreq;
/* we don't use the offset given to use for pipe reads. This
is deliberate, instead we always return the next lump of
data on the pipe */
#if 0
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
+ uint32 smb_offs = IVAL(req->vwv+3, 0);
#endif
- if (!p) {
- return(ERROR_DOS(ERRDOS,ERRbadfid));
+ if (!fsp_is_np(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
}
- set_message(inbuf,outbuf,12,0,True);
- data = smb_buf(outbuf);
-
- nread = read_from_pipe(p, data, smb_maxcnt, &unused);
+ if (fsp->vuid != req->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
- if (nread < 0) {
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ state = talloc(req, struct pipe_read_andx_state);
+ if (state == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
-
- SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
- SSVAL(smb_buf(outbuf),-2,nread);
-
- DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n",
- p->pnum, smb_mincnt, smb_maxcnt, nread));
+ req->async_priv = state;
- /* Ensure we set up the message length to include the data length read. */
- set_message_bcc(inbuf,outbuf,nread);
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
+ state->smb_maxcnt = SVAL(req->vwv+5, 0);
+ state->smb_mincnt = SVAL(req->vwv+6, 0);
-/****************************************************************************
- Reply to a close.
-****************************************************************************/
+ reply_outbuf(req, 12, state->smb_maxcnt);
+ data = (uint8_t *)smb_buf(req->outbuf);
-int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
-{
- smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
- int outsize = set_message(inbuf,outbuf,0,0,True);
+ /*
+ * We have to tell the upper layers that we're async.
+ */
+ state->outbuf = req->outbuf;
+ req->outbuf = NULL;
+
+ subreq = np_read_send(state, smbd_event_context(),
+ fsp->fake_file_handle, data,
+ state->smb_maxcnt);
+ if (subreq == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ tevent_req_set_callback(subreq, pipe_read_andx_done,
+ talloc_move(req->conn, &req));
+}
- if (!p) {
- return(ERROR_DOS(ERRDOS,ERRbadfid));
+static void pipe_read_andx_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = tevent_req_callback_data(
+ subreq, struct smb_request);
+ struct pipe_read_andx_state *state = talloc_get_type_abort(
+ req->async_priv, struct pipe_read_andx_state);
+ NTSTATUS status;
+ ssize_t nread;
+ bool is_data_outstanding;
+
+ status = np_read_recv(subreq, &nread, &is_data_outstanding);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ goto done;
}
- DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
+ req->outbuf = state->outbuf;
+ state->outbuf = NULL;
- if (!close_rpc_pipe_hnd(p)) {
- return ERROR_DOS(ERRDOS,ERRbadfid);
- }
-
- /* TODO: REMOVE PIPE FROM DB */
+ srv_set_message((char *)req->outbuf, 12, nread, False);
+
+ SSVAL(req->outbuf,smb_vwv5,nread);
+ SSVAL(req->outbuf,smb_vwv6,
+ req_wct_ofs(req)
+ + 1 /* the wct field */
+ + 12 * sizeof(uint16_t) /* vwv */
+ + 2); /* the buflen field */
+ SSVAL(req->outbuf,smb_vwv11,state->smb_maxcnt);
+
+ DEBUG(3,("readX-IPC min=%d max=%d nread=%d\n",
+ state->smb_mincnt, state->smb_maxcnt, (int)nread));
- return(outsize);
+ done:
+ chain_reply(req);
}