From fcc4efd1ea637c810eed8444080b87d7f92c837a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 11 Dec 2003 09:07:45 +0000 Subject: the next step in the dcerpc server code. Added the link between the IPC IO routines and the dcerpc endpoint servers. (This used to be commit 4929c53bc8dddda8a763fdfbcf81a79776d01113) --- source4/include/ntvfs.h | 5 +- source4/libcli/raw/rawtrans.c | 8 +- source4/librpc/rpc/dcerpc_smb.c | 2 +- source4/ntvfs/cifs/vfs_cifs.c | 8 ++ source4/ntvfs/ipc/vfs_ipc.c | 146 +++++++++++++++++++++++++++++++++++-- source4/ntvfs/simple/vfs_simple.c | 7 ++ source4/rpc_server/dcerpc_server.c | 18 +++++ source4/smbd/reply.c | 18 ----- source4/smbd/trans2.c | 53 +++++++++++++- 9 files changed, 232 insertions(+), 33 deletions(-) (limited to 'source4') diff --git a/source4/include/ntvfs.h b/source4/include/ntvfs.h index 6628402a97..88122166ee 100644 --- a/source4/include/ntvfs.h +++ b/source4/include/ntvfs.h @@ -75,8 +75,11 @@ struct ntvfs_ops { /* printing specific operations */ NTSTATUS (*lpq)(struct request_context *req, union smb_lpq *lpq); - /* trans interfaces - only used by CIFS backend to prover complete passthru for testing */ + /* trans2 interface - only used by CIFS backend to prover complete passthru for testing */ NTSTATUS (*trans2)(struct request_context *req, struct smb_trans2 *trans2); + + /* trans interface - used by IPC backend for pipes and RAP calls */ + NTSTATUS (*trans)(struct request_context *req, struct smb_trans2 *trans); }; diff --git a/source4/libcli/raw/rawtrans.c b/source4/libcli/raw/rawtrans.c index f31b1eaf7e..f7a3b4aa43 100644 --- a/source4/libcli/raw/rawtrans.c +++ b/source4/libcli/raw/rawtrans.c @@ -233,6 +233,11 @@ struct cli_request *smb_raw_trans_send_backend(struct cli_tree *tree, /* make sure we don't leak data via the padding */ memset(req->out.data, 0, padding); + if (command == SMBtrans && parms->in.trans_name) { + namelen = cli_req_append_string(req, parms->in.trans_name, + STR_TERMINATE); + } + /* primary request */ SSVAL(req->out.vwv,VWV(0),parms->in.params.length); SSVAL(req->out.vwv,VWV(1),parms->in.data.length); @@ -243,9 +248,6 @@ struct cli_request *smb_raw_trans_send_backend(struct cli_tree *tree, SIVAL(req->out.vwv,VWV(6),parms->in.timeout); SSVAL(req->out.vwv,VWV(8),0); /* reserved */ SSVAL(req->out.vwv,VWV(9),parms->in.params.length); - if (command == SMBtrans && parms->in.trans_name) - namelen = cli_req_append_string(req, parms->in.trans_name, - STR_TERMINATE); SSVAL(req->out.vwv,VWV(10),PTR_DIFF(outparam,req->out.hdr)+namelen); SSVAL(req->out.vwv,VWV(11),parms->in.data.length); SSVAL(req->out.vwv,VWV(12),PTR_DIFF(outdata,req->out.hdr)+namelen); diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index 8a7a5ca68d..9acae00249 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -309,7 +309,7 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, union smb_open io; TALLOC_CTX *mem_ctx; - asprintf(&name, "\\pipe\\%s", pipe_name); + asprintf(&name, "\\%s", pipe_name); if (!name) { return NT_STATUS_NO_MEMORY; } diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index c61749e2ad..ba2d6e7d24 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -669,6 +669,13 @@ static NTSTATUS cvfs_trans2(struct request_context *req, struct smb_trans2 *tran ASYNC_RECV_TAIL(trans2, async_trans2); } + +/* SMBtrans - not used on file shares */ +static NTSTATUS cvfs_trans(struct request_context *req, struct smb_trans2 *trans2) +{ + return NT_STATUS_ACCESS_DENIED; +} + /* initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem */ @@ -709,6 +716,7 @@ NTSTATUS ntvfs_cifs_init(void) ops.search_first = cvfs_search_first; ops.search_next = cvfs_search_next; ops.search_close = cvfs_search_close; + ops.trans = cvfs_trans; /* only define this one for trans2 testing */ ops.trans2 = cvfs_trans2; diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index 7ad02bb8cb..5ab608c46b 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -220,11 +220,9 @@ static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi) return NT_STATUS_TOO_MANY_OPENED_FILES; } - if (strncasecmp(p->pipe_name, "\\pipe\\", 6) != 0) { - talloc_destroy(mem_ctx); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + while (p->pipe_name[0] == '\\') { + p->pipe_name++; } - p->pipe_name += 6; /* we're all set, now ask the dcerpc server subsystem to open the @@ -293,7 +291,51 @@ static NTSTATUS ipc_copy(struct request_context *req, struct smb_copy *cp) */ static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd) { - return NT_STATUS_ACCESS_DENIED; + struct ipc_private *private = req->conn->ntvfs_private; + DATA_BLOB data; + uint16 fnum; + struct pipe_state *p; + NTSTATUS status; + + switch (rd->generic.level) { + case RAW_READ_READ: + fnum = rd->read.in.fnum; + data.length = rd->read.in.count; + data.data = rd->read.out.data; + break; + case RAW_READ_READX: + fnum = rd->readx.in.fnum; + data.length = rd->readx.in.maxcnt; + data.data = rd->readx.out.data; + break; + default: + return NT_STATUS_NOT_SUPPORTED; + } + + p = pipe_state_find(private, fnum); + if (!p) { + return NT_STATUS_INVALID_HANDLE; + } + + status = dcesrv_output(p->pipe_state, &data); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (rd->generic.level) { + case RAW_READ_READ: + rd->read.out.nread = data.length; + break; + case RAW_READ_READX: + rd->readx.out.remaining = 0; + rd->readx.out.compaction_mode = 0; + rd->readx.out.nread = data.length; + break; + default: + return NT_STATUS_NOT_SUPPORTED; + } + + return NT_STATUS_OK; } /* @@ -301,7 +343,52 @@ static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd) */ static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr) { - return NT_STATUS_ACCESS_DENIED; + struct ipc_private *private = req->conn->ntvfs_private; + DATA_BLOB data; + uint16 fnum; + struct pipe_state *p; + NTSTATUS status; + + switch (wr->generic.level) { + case RAW_WRITE_WRITE: + fnum = wr->write.in.fnum; + data.data = wr->write.in.data; + data.length = wr->write.in.count; + break; + + case RAW_WRITE_WRITEX: + fnum = wr->writex.in.fnum; + data.data = wr->writex.in.data; + data.length = wr->writex.in.count; + break; + + default: + return NT_STATUS_NOT_SUPPORTED; + } + + p = pipe_state_find(private, fnum); + if (!p) { + return NT_STATUS_INVALID_HANDLE; + } + + status = dcesrv_input(p->pipe_state, &data); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (wr->generic.level) { + case RAW_WRITE_WRITE: + wr->write.out.nwritten = data.length; + break; + case RAW_WRITE_WRITEX: + wr->writex.out.nwritten = data.length; + wr->writex.out.remaining = 0; + break; + default: + return NT_STATUS_NOT_SUPPORTED; + } + + return NT_STATUS_OK; } /* @@ -421,6 +508,52 @@ NTSTATUS ipc_search_close(struct request_context *req, union smb_search_close *i } +/* SMBtrans - used to provide access to SMB pipes */ +static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans) +{ + struct pipe_state *p; + struct ipc_private *private = req->conn->ntvfs_private; + NTSTATUS status; + + if (trans->in.setup_count != 2 || + trans->in.setup[0] != TRANSACT_DCERPCCMD) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* the fnum is in setup[1] */ + p = pipe_state_find(private, trans->in.setup[1]); + if (!p) { + return NT_STATUS_INVALID_HANDLE; + } + + /* pass the data to the dcerpc server. Note that we don't + expect this to fail, and things like NDR faults are not + reported at this stage. Those sorts of errors happen in the + dcesrv_output stage */ + status = dcesrv_input(p->pipe_state, &trans->in.data); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + now ask the dcerpc system for some output. This doesn't yet handle + async calls. Again, we only expect NT_STATUS_OK. If the call fails then + the error is encoded at the dcerpc level + */ + status = dcesrv_output(p->pipe_state, &trans->out.data); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + trans->out.setup_count = 0; + trans->out.setup = NULL; + trans->out.params = data_blob(NULL, 0); + + return NT_STATUS_OK; +} + + + /* initialialise the IPC backend, registering ourselves with the ntvfs subsystem */ @@ -460,6 +593,7 @@ NTSTATUS ntvfs_ipc_init(void) ops.search_first = ipc_search_first; ops.search_next = ipc_search_next; ops.search_close = ipc_search_close; + ops.trans = ipc_trans; /* register ourselves with the NTVFS subsystem. */ ret = register_backend("ntvfs", &ops); diff --git a/source4/ntvfs/simple/vfs_simple.c b/source4/ntvfs/simple/vfs_simple.c index 261ce4a19a..7972a3565a 100644 --- a/source4/ntvfs/simple/vfs_simple.c +++ b/source4/ntvfs/simple/vfs_simple.c @@ -803,6 +803,12 @@ static NTSTATUS svfs_search_close(struct request_context *req, union smb_search_ return NT_STATUS_OK; } +/* SMBtrans - not used on file shares */ +static NTSTATUS svfs_trans(struct request_context *req, struct smb_trans2 *trans2) +{ + return NT_STATUS_ACCESS_DENIED; +} + /* initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem @@ -844,6 +850,7 @@ NTSTATUS ntvfs_simple_init(void) ops.search_first = svfs_search_first; ops.search_next = svfs_search_next; ops.search_close = svfs_search_close; + ops.trans = svfs_trans; /* register ourselves with the NTVFS subsystem. We register under the name 'default' as we wish to be the default backend */ diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index c01dc4d9db..e1d6da2292 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -108,6 +108,24 @@ void dcesrv_endpoint_disconnect(struct dcesrv_state *p) } +/* + provide some input to a dcerpc endpoint server. This passes data + from a dcerpc client into the server +*/ +NTSTATUS dcesrv_input(struct dcesrv_state *p, const DATA_BLOB *data) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* + retrieve some output from a dcerpc server. The amount of data that + is wanted is in data->length +*/ +NTSTATUS dcesrv_output(struct dcesrv_state *p, DATA_BLOB *data) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + /* a useful function for implementing the query endpoint op diff --git a/source4/smbd/reply.c b/source4/smbd/reply.c index 759ec1ef05..ce203cbf93 100644 --- a/source4/smbd/reply.c +++ b/source4/smbd/reply.c @@ -2168,24 +2168,6 @@ void reply_ulogoffX(struct request_context *req) } -/**************************************************************************** - Reply to an SMBtrans request -****************************************************************************/ -void reply_trans(struct request_context *req) -{ - req_reply_error(req, NT_STATUS_FOOBAR); -} - - -/**************************************************************************** - Reply to an SMBtranss2 request -****************************************************************************/ -void reply_transs2(struct request_context *req) -{ - req_reply_error(req, NT_STATUS_FOOBAR); -} - - /**************************************************************************** Reply to an SMBfindclose request ****************************************************************************/ diff --git a/source4/smbd/trans2.c b/source4/smbd/trans2.c index 0975f77eed..3115a330e5 100644 --- a/source4/smbd/trans2.c +++ b/source4/smbd/trans2.c @@ -1214,10 +1214,20 @@ static NTSTATUS trans2_backend(struct request_context *req, struct smb_trans2 *t } +/* + backend for trans requests +*/ +static NTSTATUS trans_backend(struct request_context *req, struct smb_trans2 *trans) +{ + + return NT_STATUS_NOT_IMPLEMENTED; +} + + /**************************************************************************** - Reply to an SMBtrans2 request + Reply to an SMBtrans or SMBtrans2 request ****************************************************************************/ -void reply_trans2(struct request_context *req) +void reply_trans_generic(struct request_context *req, uint8 command) { struct smb_trans2 trans; int i; @@ -1262,6 +1272,10 @@ void reply_trans2(struct request_context *req) trans.in.setup[i] = SVAL(req->in.vwv, VWV(14+i)); } + if (command == SMBtrans) { + req_pull_string(req, &trans.in.trans_name, req->in.data, -1, STR_TERMINATE); + } + if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans.in.params) || !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans.in.data)) { req_reply_error(req, NT_STATUS_FOOBAR); @@ -1271,12 +1285,16 @@ void reply_trans2(struct request_context *req) /* is it a partial request? if so, then send a 'send more' message */ if (param_total > param_count || data_total > data_count) { - DEBUG(0,("REWRITE: not handling partial trans2 requests!\n")); + DEBUG(0,("REWRITE: not handling partial trans requests!\n")); return; } /* its a full request, give it to the backend */ - status = trans2_backend(req, &trans); + if (command == SMBtrans) { + status = trans_backend(req, &trans); + } else { + status = trans2_backend(req, &trans); + } if (!NT_STATUS_IS_OK(status)) { req_reply_error(req, status); @@ -1353,3 +1371,30 @@ void reply_trans2(struct request_context *req) req_send_reply(req); } while (params_left != 0 || data_left != 0); } + + +/**************************************************************************** + Reply to an SMBtrans2 +****************************************************************************/ +void reply_trans2(struct request_context *req) +{ + reply_trans_generic(req, SMBtrans2); +} + +/**************************************************************************** + Reply to an SMBtrans +****************************************************************************/ +void reply_trans(struct request_context *req) +{ + reply_trans_generic(req, SMBtrans); +} + +/**************************************************************************** + Reply to an SMBtranss2 request +****************************************************************************/ +void reply_transs2(struct request_context *req) +{ + req_reply_error(req, NT_STATUS_FOOBAR); +} + + -- cgit