diff options
-rw-r--r-- | source4/ntvfs/ipc/vfs_ipc.c | 32 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 49 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_sock.c | 11 |
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) |