1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-13 08:23:49 +03:00

Big update moving the multi-pdu support from 2.0.x into HEAD for JF

and the printer functions.
Also tidied up some header includes and got the order right so you
can now do a :

make proto
make clean
make

Jeremy.
(This used to be commit 833cd9fba9)
This commit is contained in:
Jeremy Allison
2000-03-09 21:45:16 +00:00
parent 18465ec2cd
commit 6bb92a6d38
12 changed files with 1699 additions and 231 deletions

View File

@@ -1,4 +1,3 @@
/*
* Unix SMB/Netbios implementation.
* Version 1.9.
@@ -78,67 +77,61 @@ void init_rpc_pipe_hnd(void)
Initialise an outgoing packet.
****************************************************************************/
BOOL pipe_init_outgoing_data(output_data *out_data)
BOOL pipe_init_outgoing_data(output_data *o_data)
{
memset(out_data->current_pdu, '\0', sizeof(out_data->current_pdu));
memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu));
/* Free any memory in the current return data buffer. */
prs_mem_free(&out_data->rdata);
prs_mem_free(&o_data->rdata);
/*
* Initialize the outgoing RPC data buffer.
* we will use this as the raw data area for replying to rpc requests.
*/
if(!prs_init(&out_data->rdata, 1024, 4, MARSHALL)) {
if(!prs_init(&o_data->rdata, MAX_PDU_FRAG_LEN, 4, MARSHALL)) {
DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n"));
return False;
}
/* Reset the offset counters. */
out_data->data_sent_length = 0;
out_data->current_pdu_len = 0;
out_data->current_pdu_sent = 0;
o_data->data_sent_length = 0;
o_data->current_pdu_len = 0;
o_data->current_pdu_sent = 0;
return True;
}
/****************************************************************************
Find first available pipe slot.
HACK !!! Attempt to find a remote process to communicate RPC's with.
****************************************************************************/
pipes_struct *open_rpc_pipe_p(char *pipe_name,
connection_struct *conn, uint16 vuid)
static void attempt_remote_rpc_connect(pipes_struct *p)
{
int i;
pipes_struct *p;
static int next_pipe;
struct msrpc_state *m = NULL;
user_struct *vuser = get_valid_user_struct(vuid);
struct user_creds usr;
struct msrpc_state *m;
user_struct *vuser = get_valid_user_struct(p->vuid);
p->m = NULL;
if (vuser == NULL) {
DEBUG(4,("attempt_remote_rpc_connect: invalid vuid %d\n", (int)p->vuid));
return;
}
ZERO_STRUCT(usr);
DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
pipe_name, pipes_open));
if (vuser == NULL)
{
DEBUG(4,("invalid vuid %d\n", vuid));
return NULL;
}
/* set up unix credentials from the smb side, to feed over the pipe */
make_creds_unix(&usr.uxc, vuser->name, vuser->requested_name,
vuser->real_name, vuser->guest);
vuser->real_name, vuser->guest);
usr.ptr_uxc = 1;
make_creds_unix_sec(&usr.uxs, vuser->uid, vuser->gid,
vuser->n_groups, vuser->groups);
vuser->n_groups, vuser->groups);
usr.ptr_uxs = 1;
usr.ptr_ssk = 1;
DEBUG(0,("user session key not available (yet).\n"));
DEBUG(0,("password-change operations may fail.\n"));
DEBUG(10,("user session key not available (yet).\n"));
DEBUG(10,("password-change operations may fail.\n"));
#if USER_SESSION_KEY_DEFINED_IN_VUSER_STRUCT
memcpy(usr.usr_sess_key, vuser->usr_sess_key, sizeof(usr.usr_sess_key));
@@ -153,14 +146,28 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name,
*/
become_root(False); /* to connect to pipe */
m = msrpc_use_add(pipe_name, getpid(), &usr, False);
p->m = msrpc_use_add(p->name, getpid(), &usr, False);
unbecome_root(False);
if (m == NULL)
{
DEBUG(10,("open pipes: msrpc redirect failed - go local.\n"));
}
if (p->m == NULL)
DEBUG(10,("attempt_remote_rpc_connect: msrpc redirect failed - using local implementation.\n"));
}
/****************************************************************************
Find first available pipe slot.
****************************************************************************/
pipes_struct *open_rpc_pipe_p(char *pipe_name,
connection_struct *conn, uint16 vuid)
{
int i;
pipes_struct *p;
static int next_pipe;
DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
pipe_name, pipes_open));
/* not repeating pipe numbers makes it easier to track things in
log files and prevents client bugs where pipe numbers are reused
over connection restarts */
@@ -180,18 +187,26 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name,
DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));
p = (pipes_struct *)malloc(sizeof(*p));
if (!p)
return NULL;
ZERO_STRUCTP(p);
/*
* Initialize the RPC and PDU data buffers with no memory.
*/
prs_init(&p->out_data.rdata, 0, 4, MARSHALL);
DLIST_ADD(Pipes, p);
/*
* Initialize the incoming RPC data buffer with one PDU worth of memory.
* We cheat here and say we're marshalling, as we intend to add incoming
* data directly into the prs_struct and we want it to auto grow. We will
* change the type to UNMARSALLING before processing the stream.
*/
if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, 4, MARSHALL)) {
DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
return NULL;
}
bitmap_set(bmap, i);
i += pipe_handle_offset;
@@ -204,8 +219,6 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name,
p->priority = 0;
p->conn = conn;
p->vuid = vuid;
p->m = m;
p->max_trans_reply = 0;
@@ -213,15 +226,40 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name,
p->ntlmssp_auth_validated = False;
p->ntlmssp_auth_requested = False;
p->pipe_bound = False;
p->fault_state = False;
/*
* Initialize the incoming RPC struct.
*/
p->in_data.pdu_needed_len = 0;
p->in_data.pdu_received_len = 0;
/*
* Initialize the outgoing RPC struct.
*/
p->out_data.current_pdu_len = 0;
p->out_data.current_pdu_sent = 0;
p->out_data.data_sent_length = 0;
/*
* Initialize the outgoing RPC data buffer with no memory.
*/
prs_init(&p->out_data.rdata, 0, 4, MARSHALL);
p->uid = (uid_t)-1;
p->gid = (gid_t)-1;
fstrcpy(p->name, pipe_name);
/*
* HACK !!! For Luke - attempt to connect to RPC redirect process.
*/
attempt_remote_rpc_connect(p);
DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n",
pipe_name, i, pipes_open));
@@ -234,27 +272,408 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name,
return chain_p;
}
/****************************************************************************
Sets the fault state on incoming packets.
****************************************************************************/
static void set_incoming_fault(pipes_struct *p)
{
prs_mem_free(&p->in_data.data);
p->in_data.pdu_needed_len = 0;
p->in_data.pdu_received_len = 0;
p->fault_state = True;
DEBUG(10,("set_incoming_fault: Setting fault state on pipe %s : pnum = 0x%x\n",
p->name, p->pnum ));
}
/****************************************************************************
Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer.
****************************************************************************/
static ssize_t fill_rpc_header(pipes_struct *p, char *data, size_t data_to_copy)
{
size_t len_needed_to_complete_hdr = MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu_received_len);
DEBUG(10,("fill_rpc_header: data_to_copy = %u, len_needed_to_complete_hdr = %u, receive_len = %u\n",
(unsigned int)data_to_copy, (unsigned int)len_needed_to_complete_hdr,
(unsigned int)p->in_data.pdu_received_len ));
memcpy((char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, len_needed_to_complete_hdr);
p->in_data.pdu_received_len += len_needed_to_complete_hdr;
return (ssize_t)len_needed_to_complete_hdr;
}
/****************************************************************************
Unmarshalls a new PDU header. Assumes the raw header data is in current_in_pdu.
****************************************************************************/
static ssize_t unmarshall_rpc_header(pipes_struct *p)
{
/*
* Unmarshall the header to determine the needed length.
*/
prs_struct rpc_in;
if(p->in_data.pdu_received_len != RPC_HEADER_LEN) {
DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n"));
set_incoming_fault(p);
return -1;
}
prs_init( &rpc_in, 0, 4, UNMARSHALL);
prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0],
p->in_data.pdu_received_len, False);
/*
* Unmarshall the header as this will tell us how much
* data we need to read to get the complete pdu.
*/
if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) {
DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n"));
set_incoming_fault(p);
return -1;
}
/*
* Validate the RPC header.
*/
if(p->hdr.major != 5 && p->hdr.minor != 0) {
DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n"));
set_incoming_fault(p);
return -1;
}
/*
* If there is no data in the incoming buffer and it's a requst pdu then
* ensure that the FIRST flag is set. If not then we have
* a stream missmatch.
*/
if((p->hdr.pkt_type == RPC_REQUEST) && (prs_offset(&p->in_data.data) == 0) && !(p->hdr.flags & RPC_FLG_FIRST)) {
DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n"));
set_incoming_fault(p);
return -1;
}
/*
* Ensure that the pdu length is sane.
*/
if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) {
DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n"));
set_incoming_fault(p);
return -1;
}
DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type,
(unsigned int)p->hdr.flags ));
/*
* Adjust for the header we just ate.
*/
p->in_data.pdu_received_len = 0;
p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN;
/*
* Null the data we just ate.
*/
memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN);
return 0; /* No extra data processed. */
}
/****************************************************************************
Processes a request pdu. This will do auth processing if needed, and
appends the data into the complete stream if the LAST flag is not set.
****************************************************************************/
static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
{
BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN);
size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
(auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
if(!p->pipe_bound) {
DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
set_incoming_fault(p);
return False;
}
/*
* Check if we need to do authentication processing.
* This is only done on requests, not binds.
*/
/*
* Read the RPC request header.
*/
if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) {
DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n"));
set_incoming_fault(p);
return False;
}
if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) {
DEBUG(0,("process_request_pdu: failed to do auth processing.\n"));
set_incoming_fault(p);
return False;
}
if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) {
/*
* Authentication _was_ requested and it already failed.
*/
DEBUG(0,("process_request_pdu: RPC request received on pipe %s where \
authentication failed. Denying the request.\n", p->name));
set_incoming_fault(p);
return False;
}
/*
* Check the data length doesn't go over the 1Mb limit.
*/
if(prs_data_size(&p->in_data.data) + data_len > 1024*1024) {
DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n",
(unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len ));
set_incoming_fault(p);
return False;
}
/*
* Append the data portion into the buffer and return.
*/
{
char *data_from = prs_data_p(rpc_in_p) + prs_offset(rpc_in_p);
if(!prs_append_data(&p->in_data.data, data_from, data_len)) {
DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n",
(unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) ));
set_incoming_fault(p);
return False;
}
}
if(p->hdr.flags & RPC_FLG_LAST) {
BOOL ret;
/*
* Ok - we finally have a complete RPC stream.
* Call the rpc command to process it.
*/
/*
* Set the parse offset to the start of the data and set the
* prs_struct to UNMARSHALL.
*/
prs_set_offset(&p->in_data.data, 0);
prs_switch_type(&p->in_data.data, UNMARSHALL);
/*
* Process the complete data stream here.
*/
ret = api_pipe_request(p);
/*
* We have consumed the whole data stream. Set back to
* marshalling and set the offset back to the start of
* the buffer to re-use it (we could also do a prs_mem_free()
* and then re_init on the next start of PDU. Not sure which
* is best here.... JRA.
*/
prs_switch_type(&p->in_data.data, MARSHALL);
prs_set_offset(&p->in_data.data, 0);
return ret;
}
return True;
}
/****************************************************************************
Processes a finished PDU stored in current_in_pdu. The RPC_HEADER has
already been parsed and stored in p->hdr.
****************************************************************************/
static ssize_t process_complete_pdu(pipes_struct *p)
{
prs_struct rpc_in;
size_t data_len = p->in_data.pdu_received_len;
char *data_p = (char *)&p->in_data.current_in_pdu[0];
BOOL reply = False;
if(p->fault_state) {
DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n",
p->name ));
set_incoming_fault(p);
setup_fault_pdu(p);
return (ssize_t)data_len;
}
prs_init( &rpc_in, 0, 4, UNMARSHALL);
prs_give_memory( &rpc_in, data_p, (uint32)data_len, False);
DEBUG(10,("process_complete_pdu: processing packet type %u\n",
(unsigned int)p->hdr.pkt_type ));
switch (p->hdr.pkt_type) {
case RPC_BIND:
case RPC_ALTCONT:
/*
* We assume that a pipe bind is only in one pdu.
*/
reply = api_pipe_bind_req(p, &rpc_in);
break;
case RPC_BINDRESP:
/*
* We assume that a pipe bind_resp is only in one pdu.
*/
reply = api_pipe_bind_auth_resp(p, &rpc_in);
break;
case RPC_REQUEST:
reply = process_request_pdu(p, &rpc_in);
break;
default:
DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type ));
break;
}
if (!reply) {
DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name));
set_incoming_fault(p);
setup_fault_pdu(p);
} else {
/*
* Reset the lengths. We're ready for a new pdu.
*/
p->in_data.pdu_needed_len = 0;
p->in_data.pdu_received_len = 0;
}
return (ssize_t)data_len;
}
/****************************************************************************
Accepts incoming data on an rpc pipe. Processes the data in pdu sized units.
****************************************************************************/
static ssize_t process_incoming_data(pipes_struct *p, char *data, size_t n)
{
size_t data_to_copy = MIN(n, MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len);
DEBUG(10,("process_incoming_data: Start: pdu_received_len = %u, pdu_needed_len = %u, incoming data = %u\n",
(unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len,
(unsigned int)n ));
if(data_to_copy == 0) {
/*
* This is an error - data is being received and there is no
* space in the PDU. Free the received data and go into the fault state.
*/
DEBUG(0,("process_incoming_data: No space in incoming pdu buffer. Current size = %u \
incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned int)n ));
set_incoming_fault(p);
return -1;
}
/*
* If we have no data already, wait until we get at least a RPC_HEADER_LEN
* number of bytes before we can do anything.
*/
if((p->in_data.pdu_needed_len == 0) && (p->in_data.pdu_received_len < RPC_HEADER_LEN)) {
/*
* Always return here. If we have more data then the RPC_HEADER
* will be processed the next time around the loop.
*/
return fill_rpc_header(p, data, data_to_copy);
}
/*
* At this point we know we have at least an RPC_HEADER_LEN amount of data
* stored in current_in_pdu.
*/
/*
* If pdu_needed_len is zero this is a new pdu.
* Unmarshall the header so we know how much more
* data we need, then loop again.
*/
if(p->in_data.pdu_needed_len == 0)
return unmarshall_rpc_header(p);
/*
* Ok - at this point we have a valid RPC_HEADER in p->hdr.
* Keep reading until we have a full pdu.
*/
data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len);
/*
* Copy as much of the data as we need into the current_in_pdu buffer.
*/
memcpy( (char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, data_to_copy);
p->in_data.pdu_received_len += data_to_copy;
/*
* Do we have a complete PDU ?
*/
if(p->in_data.pdu_received_len == p->in_data.pdu_needed_len)
return process_complete_pdu(p);
DEBUG(10,("process_incoming_data: not a complete PDU yet. pdu_received_len = %u, pdu_needed_len = %u\n",
(unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len ));
return (ssize_t)data_to_copy;
}
/****************************************************************************
Accepts incoming data on an rpc pipe.
This code is probably incorrect at the moment. The problem is
that the rpc request shouldn't really be executed until all the
data needed for it is received. This currently assumes that each
SMBwrite or SMBwriteX contains all the data needed for an rpc
request. JRA.
****************************************************************************/
****************************************************************************/
ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n)
{
size_t data_left = n;
DEBUG(6,("write_to_pipe: %x", p->pnum));
DEBUG(6,("name: %s open: %s len: %d",
DEBUG(6,(" name: %s open: %s len: %d\n",
p->name, BOOLSTR(p->open), (int)n));
dump_data(50, data, n);
return rpc_command(p, data, (int)n) ? ((ssize_t)n) : -1;
while(data_left) {
ssize_t data_used;
DEBUG(10,("write_to_pipe: data_left = %u\n", (unsigned int)data_left ));
data_used = process_incoming_data(p, data, data_left);
DEBUG(10,("write_to_pipe: data_used = %d\n", (int)data_used ));
if(data_used < 0)
return -1;
data_left -= data_used;
data += data_used;
}
return n;
}
@@ -282,7 +701,7 @@ int read_from_pipe(pipes_struct *p, char *data, int n)
DEBUG(6,("read_from_pipe: %x", p->pnum));
DEBUG(6,("name: %s len: %d\n", p->name, n));
DEBUG(6,(" name: %s len: %d\n", p->name, n));
/*
* We cannot return more than one PDU length per
@@ -320,8 +739,9 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len,
* may of course be zero if this is the first return fragment.
*/
DEBUG(10,("read_from_pipe: %s: data_sent_length = %u, prs_offset(&p->out_data.rdata) = %u.\n",
p->name, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) ));
DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length \
= %u, prs_offset(&p->out_data.rdata) = %u.\n",
p->name, (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) ));
if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) {
/*
@@ -415,22 +835,17 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn)
pipes_open--;
if (p->m != NULL) {
DEBUG(4,("close_rpc_pipe_hnd: closing msrpc redirect: "));
if (msrpc_use_del(p->m->pipe_name, &p->m->usr, False, NULL))
DEBUG(4,("OK\n"));
else
DEBUG(4,("FAILED\n"));
}
DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n",
p->name, p->pnum, pipes_open));
if (p->m != NULL)
{
DEBUG(4,("closed msrpc redirect: "));
if (msrpc_use_del(p->m->pipe_name, &p->m->usr, False, NULL))
{
DEBUG(4,("OK\n"));
}
else
{
DEBUG(4,("FAILED\n"));
}
}
DLIST_REMOVE(Pipes, p);
ZERO_STRUCTP(p);