Read from a RPC named pipe
********************************************************************/
static NTSTATUS rpc_read_np(struct cli_state *cli, const char *pipe_name,
- int fnum, char *buf, off_t offset, size_t size,
+ int fnum, char *buf, size_t size,
ssize_t *pnum_read)
{
ssize_t num_read;
- num_read = cli_read(cli, fnum, buf, offset, size);
+ num_read = cli_read(cli, fnum, buf, 0, size);
- DEBUG(5,("rpc_read_np: num_read = %d, read offset: %u, to read: %u\n",
- (int)num_read, (unsigned int)offset, (unsigned int)size));
+ DEBUG(5,("rpc_read_np: num_read = %d, to read: %u\n", (int)num_read,
+ (unsigned int)size));
/*
* A dos error of ERRDOS/ERRmoredata is not an error.
return NT_STATUS_OK;
}
+/*
+ * Realloc pdu to have a least "size" bytes
+ */
+
+static bool rpc_grow_buffer(prs_struct *pdu, size_t size)
+{
+ size_t extra_size;
+
+ if (prs_data_size(pdu) >= size) {
+ return true;
+ }
+
+ extra_size = size - prs_data_size(pdu);
+
+ if (!prs_force_grow(pdu, extra_size)) {
+ DEBUG(0, ("rpc_grow_buffer: Failed to grow parse struct by "
+ "%d bytes.\n", (int)extra_size));
+ return false;
+ }
+
+ DEBUG(5, ("rpc_grow_buffer: grew buffer by %d bytes to %u\n",
+ (int)extra_size, prs_data_size(pdu)));
+ return true;
+}
+
/*******************************************************************
Use SMBreadX to get rest of one fragment's worth of rpc data.
- Will expand the current_pdu struct to the correct size.
+ Reads the whole size or give an error message
********************************************************************/
static NTSTATUS rpc_read(struct rpc_pipe_client *cli,
prs_struct *current_pdu,
- uint32 data_to_read,
- uint32 *current_pdu_offset)
+ size_t size,
+ uint32 current_pdu_offset)
{
- size_t size = (size_t)cli->max_recv_frag;
- uint32 stream_offset = 0;
ssize_t num_read = 0;
char *pdata;
- ssize_t extra_data_size = ((ssize_t)*current_pdu_offset) + ((ssize_t)data_to_read) - (ssize_t)prs_data_size(current_pdu);
-
- DEBUG(5,("rpc_read: data_to_read: %u current_pdu offset: %u extra_data_size: %d\n",
- (unsigned int)data_to_read, (unsigned int)*current_pdu_offset, (int)extra_data_size ));
- /*
- * Grow the buffer if needed to accommodate the data to be read.
- */
+ DEBUG(5, ("rpc_read: data_to_read: %u current_pdu offset: %d\n",
+ (unsigned int)size, (unsigned int)current_pdu_offset));
- if (extra_data_size > 0) {
- if(!prs_force_grow(current_pdu, (uint32)extra_data_size)) {
- DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", (int)extra_data_size ));
- return NT_STATUS_NO_MEMORY;
- }
- DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", (int)extra_data_size, prs_data_size(current_pdu) ));
- }
-
- pdata = prs_data_p(current_pdu) + *current_pdu_offset;
+ pdata = prs_data_p(current_pdu) + current_pdu_offset;
- do {
+ while (num_read < size) {
+ ssize_t thistime = 0;
NTSTATUS status;
- /* read data using SMBreadX */
- if (size > (size_t)data_to_read) {
- size = (size_t)data_to_read;
- }
-
switch (cli->transport_type) {
case NCACN_NP:
status = rpc_read_np(cli->trans.np.cli,
cli->trans.np.pipe_name,
- cli->trans.np.fnum, pdata,
- (off_t)stream_offset, size,
- &num_read);
+ cli->trans.np.fnum,
+ pdata + num_read,
+ size - num_read, &thistime);
break;
case NCACN_IP_TCP:
case NCACN_UNIX_STREAM:
status = NT_STATUS_OK;
- num_read = sys_read(cli->trans.sock.fd, pdata, size);
- if (num_read == -1) {
+ thistime = sys_read(cli->trans.sock.fd,
+ pdata + num_read,
+ size - num_read);
+ if (thistime == -1) {
status = map_nt_error_from_unix(errno);
}
- if (num_read == 0) {
- status = NT_STATUS_END_OF_FILE;
- }
break;
default:
DEBUG(0, ("unknown transport type %d\n",
return NT_STATUS_INTERNAL_ERROR;
}
- data_to_read -= num_read;
- stream_offset += num_read;
- pdata += num_read;
+ if (thistime == 0) {
+ status = NT_STATUS_END_OF_FILE;
+ }
- } while (num_read > 0 && data_to_read > 0);
- /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ num_read += thistime;
+
+ }
- /*
- * Update the current offset into current_pdu by the amount read.
- */
- *current_pdu_offset += stream_offset;
return NT_STATUS_OK;
}
/* Ensure we have at least RPC_HEADER_LEN worth of data to parse. */
if (current_pdu_len < RPC_HEADER_LEN) {
- /* rpc_read expands the current_pdu struct as neccessary. */
- ret = rpc_read(cli, current_pdu, RPC_HEADER_LEN - current_pdu_len, ¤t_pdu_len);
+ if (!rpc_grow_buffer(current_pdu, RPC_HEADER_LEN)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ret = rpc_read(cli, current_pdu,
+ RPC_HEADER_LEN - current_pdu_len,
+ current_pdu_len);
if (!NT_STATUS_IS_OK(ret)) {
return ret;
}
+ current_pdu_len = RPC_HEADER_LEN;
}
/* This next call sets the endian bit correctly in current_pdu. */
return NT_STATUS_BUFFER_TOO_SMALL;
}
+ if (prhdr->frag_len > cli->max_recv_frag) {
+ DEBUG(0, ("cli_pipe_get_current_pdu: Server sent fraglen %d,"
+ " we only allow %d\n", (int)prhdr->frag_len,
+ (int)cli->max_recv_frag));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
/* Ensure we have frag_len bytes of data. */
if (current_pdu_len < prhdr->frag_len) {
- /* rpc_read expands the current_pdu struct as neccessary. */
- ret = rpc_read(cli, current_pdu, (uint32)prhdr->frag_len - current_pdu_len, ¤t_pdu_len);
+ if (!rpc_grow_buffer(current_pdu, prhdr->frag_len)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ret = rpc_read(cli, current_pdu,
+ (uint32)prhdr->frag_len - current_pdu_len,
+ current_pdu_len);
if (!NT_STATUS_IS_OK(ret)) {
return ret;
}
}
- if (current_pdu_len < prhdr->frag_len) {
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
return NT_STATUS_OK;
}
return NT_STATUS_OK;
}
+/****************************************************************************
+ Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
+****************************************************************************/
+
+static bool cli_api_pipe(struct cli_state *cli, const char *pipe_name,
+ uint16 *setup, uint32 setup_count,
+ uint32 max_setup_count,
+ char *params, uint32 param_count,
+ uint32 max_param_count,
+ char *data, uint32 data_count,
+ uint32 max_data_count,
+ char **rparam, uint32 *rparam_count,
+ char **rdata, uint32 *rdata_count)
+{
+ cli_send_trans(cli, SMBtrans,
+ pipe_name,
+ 0,0, /* fid, flags */
+ setup, setup_count, max_setup_count,
+ params, param_count, max_param_count,
+ data, data_count, max_data_count);
+
+ return (cli_receive_trans(cli, SMBtrans,
+ rparam, (unsigned int *)rparam_count,
+ rdata, (unsigned int *)rdata_count));
+}
+
/****************************************************************************
Send data on an rpc pipe via trans. The prs_struct data must be the last
pdu fragment of an NDR data stream.
goto fail;
}
- result->trans.sock.fd = open_socket_out(SOCK_STREAM, &addr, port, 60);
- if (result->trans.sock.fd == -1) {
- status = map_nt_error_from_unix(errno);
+ status = open_socket_out(&addr, port, 60, &result->trans.sock.fd);
+ if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
result->srv_name_slash = talloc_asprintf_strupper_m(
result, "\\\\%s", result->desthost);
+ result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
+ result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
+
if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
TALLOC_FREE(result);
return NT_STATUS_NO_MEMORY;
auth->user_name = talloc_strdup(auth, cli->user_name);
auth->domain = talloc_strdup(auth, cli->domain);
+ auth->user_session_key = data_blob_talloc(auth,
+ cli->user_session_key.data,
+ cli->user_session_key.length);
if ((auth->user_name == NULL) || (auth->domain == NULL)) {
TALLOC_FREE(result);
cli->auth->a_u.kerberos_auth->session_key.length);
break;
case PIPE_AUTH_TYPE_NONE:
+ *session_key = data_blob_talloc(mem_ctx,
+ cli->auth->user_session_key.data,
+ cli->auth->user_session_key.length);
+ break;
default:
return NT_STATUS_NO_USER_SESSION_KEY;
}