summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c32
-rw-r--r--source4/rpc_server/dcerpc_server.c49
-rw-r--r--source4/rpc_server/dcerpc_sock.c11
3 files changed, 44 insertions, 48 deletions
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index 68c59b7502..2c148fbd0c 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -350,6 +350,18 @@ static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
return NT_STATUS_ACCESS_DENIED;
}
+static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
+{
+ DATA_BLOB *blob = private_data;
+
+ if (out->length < blob->length) {
+ blob->length = out->length;
+ }
+ memcpy(blob->data, out->data, blob->length);
+ *nwritten = blob->length;
+ return NT_STATUS_OK;
+}
+
/*
read from a file
*/
@@ -380,7 +392,7 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
}
if (data.length != 0) {
- status = dcesrv_output_blob(p->dce_conn, &data);
+ status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
if (NT_STATUS_IS_ERR(status)) {
return status;
}
@@ -604,6 +616,22 @@ static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_ACCESS_DENIED;
}
+static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DATA_BLOB *blob = private_data;
+
+ if (out->length > blob->length) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (out->length < blob->length) {
+ blob->length = out->length;
+ }
+ memcpy(blob->data, out->data, blob->length);
+ *nwritten = blob->length;
+ return status;
+}
/* SMBtrans - handle a DCERPC command */
static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
@@ -638,7 +666,7 @@ static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
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_blob(p->dce_conn, &trans->out.data);
+ status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
if (NT_STATUS_IS_ERR(status)) {
return status;
}
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 87f8c9a421..15da8c6964 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1100,20 +1100,19 @@ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
The first argument to write_fn() will be 'private', the second will
be a pointer to a buffer containing the data to be sent and the 3rd
- will be the number of bytes to be sent.
+ will be a pointer to a size_t variable that will be set to the
+ number of bytes that are consumed from the output.
- write_fn() should return the number of bytes successfully written.
-
- this will return STATUS_BUFFER_OVERFLOW if there is more to be written
from the current fragment
*/
NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
- void *private,
- ssize_t (*write_fn)(void *, DATA_BLOB *))
+ void *private_data,
+ NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
{
+ NTSTATUS status;
struct dcesrv_call_state *call;
struct dcesrv_call_reply *rep;
- ssize_t nwritten;
+ size_t nwritten;
call = dce_conn->call_list;
if (!call || !call->replies) {
@@ -1128,12 +1127,8 @@ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
}
rep = call->replies;
- nwritten = write_fn(private, &rep->data);
- if (nwritten == -1) {
- /* TODO: hmm, how do we cope with this? destroy the
- connection perhaps? */
- return NT_STATUS_UNSUCCESSFUL;
- }
+ status = write_fn(private_data, &rep->data, &nwritten);
+ NT_STATUS_IS_ERR_RETURN(status);
rep->data.length -= nwritten;
rep->data.data += nwritten;
@@ -1141,8 +1136,6 @@ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
if (rep->data.length == 0) {
/* we're done with this section of the call */
DLIST_REMOVE(call->replies, rep);
- } else {
- return STATUS_BUFFER_OVERFLOW;
}
if (call->replies == NULL) {
@@ -1151,31 +1144,7 @@ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
talloc_free(call);
}
- return NT_STATUS_OK;
-}
-
-
-/*
- write_fn() for dcesrv_output_blob()
-*/
-static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
-{
- DATA_BLOB *blob = private;
- if (out->length < blob->length) {
- blob->length = out->length;
- }
- memcpy(blob->data, out->data, blob->length);
- return blob->length;
-}
-
-/*
- a simple wrapper for dcesrv_output() for when we want to output
- into a data blob
-*/
-NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
- DATA_BLOB *blob)
-{
- return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
+ return status;
}
static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
diff --git a/source4/rpc_server/dcerpc_sock.c b/source4/rpc_server/dcerpc_sock.c
index 317655cfcf..5bba948c08 100644
--- a/source4/rpc_server/dcerpc_sock.c
+++ b/source4/rpc_server/dcerpc_sock.c
@@ -38,18 +38,17 @@ struct dcesrv_socket_context {
/*
write_fn callback for dcesrv_output()
*/
-static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out)
+static NTSTATUS dcerpc_write_fn(void *private_data, DATA_BLOB *out, size_t *nwritten)
{
NTSTATUS status;
- struct socket_context *sock = private;
+ struct socket_context *sock = talloc_get_type(private_data, struct socket_context);
size_t sendlen;
status = socket_send(sock, out, &sendlen, 0);
- if (NT_STATUS_IS_ERR(status)) {
- return -1;
- }
+ NT_STATUS_IS_ERR_RETURN(status);
- return sendlen;
+ *nwritten = sendlen;
+ return status;
}
static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)