diff options
author | Jeremy Allison <jra@samba.org> | 2005-11-29 02:10:52 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:05:39 -0500 |
commit | 05fafb83968a31907d996d37b91bdd9b72998701 (patch) | |
tree | 42a4f05466871b10f9c7b4535423b5adc76a45ec | |
parent | 6f04dc477e273f782454c798f26f2d24c2a83574 (diff) | |
download | samba-05fafb83968a31907d996d37b91bdd9b72998701.tar.gz samba-05fafb83968a31907d996d37b91bdd9b72998701.tar.bz2 samba-05fafb83968a31907d996d37b91bdd9b72998701.zip |
r11950: If we got a connection oriented cancel pdu we would spin processing it.
Fix that, and also add in comments for all possible CL and CO PDU
types. Make sure we process them correctly.
Jeremy.
(This used to be commit 672113a627aa9060795871bc2ea3a02e696d7d7d)
-rw-r--r-- | source3/include/rpc_dce.h | 30 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 49 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe_hnd.c | 81 |
3 files changed, 148 insertions, 12 deletions
diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h index 3de4d2b691..e718d92271 100644 --- a/source3/include/rpc_dce.h +++ b/source3/include/rpc_dce.h @@ -26,15 +26,27 @@ /* DCE/RPC packet types */ enum RPC_PKT_TYPE { - RPC_REQUEST = 0x00, - RPC_RESPONSE = 0x02, - RPC_FAULT = 0x03, - RPC_BIND = 0x0B, - RPC_BINDACK = 0x0C, - RPC_BINDNACK = 0x0D, - RPC_ALTCONT = 0x0E, - RPC_ALTCONTRESP = 0x0F, - RPC_AUTH3 = 0x10 /* not the real name! this is undocumented! */ + RPC_REQUEST = 0x00, /* Ordinary request. */ + RPC_PING = 0x01, /* Connectionless is server alive ? */ + RPC_RESPONSE = 0x02, /* Ordinary reply. */ + RPC_FAULT = 0x03, /* Fault in processing of call. */ + RPC_WORKING = 0x04, /* Connectionless reply to a ping when server busy. */ + RPC_NOCALL = 0x05, /* Connectionless reply to a ping when server has lost part of clients call. */ + RPC_REJECT = 0x06, /* Refuse a request with a code. */ + RPC_ACK = 0x07, /* Connectionless client to server code. */ + RPC_CL_CANCEL= 0x08, /* Connectionless cancel. */ + RPC_FACK = 0x09, /* Connectionless fragment ack. Both client and server send. */ + RPC_CANCEL_ACK = 0x0A, /* Server ACK to client cancel request. */ + RPC_BIND = 0x0B, /* Bind to interface. */ + RPC_BINDACK = 0x0C, /* Server ack of bind. */ + RPC_BINDNACK = 0x0D, /* Server nack of bind. */ + RPC_ALTCONT = 0x0E, /* Alter auth. */ + RPC_ALTCONTRESP = 0x0F, /* Reply to alter auth. */ + RPC_AUTH3 = 0x10, /* not the real name! this is undocumented! */ + RPC_SHUTDOWN = 0x11, /* Server to client request to shutdown. */ + RPC_CO_CANCEL= 0x12, /* Connection-oriented cancel request. */ + RPC_ORPHANED = 0x13 /* Client telling server it's aborting a partially sent request or telling + server to stop sending replies. */ }; /* DCE/RPC flags */ diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index b615080d34..8084e7673a 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -892,6 +892,55 @@ BOOL setup_fault_pdu(pipes_struct *p, NTSTATUS status) return True; } +#if 0 +/******************************************************************* + Marshall a cancel_ack pdu. + We should probably check the auth-verifier here. +*******************************************************************/ + +BOOL setup_cancel_ack_reply(pipes_struct *p, prs_struct *rpc_in_p) +{ + prs_struct outgoing_pdu; + RPC_HDR ack_reply_hdr; + + /* Free any memory in the current return data buffer. */ + prs_mem_free(&p->out_data.rdata); + + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + + prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL); + prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False); + + /* + * Initialize a cancel_ack header. + */ + + init_rpc_hdr(&ack_reply_hdr, RPC_CANCEL_ACK, RPC_FLG_FIRST | RPC_FLG_LAST, + p->hdr.call_id, RPC_HEADER_LEN, 0); + + /* + * Marshall the header into the outgoing PDU. + */ + + if(!smb_io_rpc_hdr("", &ack_reply_hdr, &outgoing_pdu, 0)) { + DEBUG(0,("setup_cancel_ack_reply: marshalling of RPC_HDR failed.\n")); + prs_mem_free(&outgoing_pdu); + return False; + } + + p->out_data.data_sent_length = 0; + p->out_data.current_pdu_len = prs_offset(&outgoing_pdu); + p->out_data.current_pdu_sent = 0; + + prs_mem_free(&outgoing_pdu); + return True; +} +#endif + /******************************************************************* Ensure a bind request has the correct abstract & transfer interface. Used to reject unknown binds from Win2k. diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index 6077faed16..5fb84115cc 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -716,6 +716,32 @@ static void process_complete_pdu(pipes_struct *p) (unsigned int)p->hdr.pkt_type )); switch (p->hdr.pkt_type) { + case RPC_REQUEST: + reply = process_request_pdu(p, &rpc_in); + break; + + case RPC_PING: /* CL request - ignore... */ + DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", + (unsigned int)p->hdr.pkt_type, p->name)); + break; + + case RPC_RESPONSE: /* No responses here. */ + DEBUG(0,("process_complete_pdu: Error. RPC_RESPONSE received from client on pipe %s.\n", + p->name )); + break; + + case RPC_FAULT: + case RPC_WORKING: /* CL request - reply to a ping when a call in process. */ + case RPC_NOCALL: /* CL - server reply to a ping call. */ + case RPC_REJECT: + case RPC_ACK: + case RPC_CL_CANCEL: + case RPC_FACK: + case RPC_CANCEL_ACK: + DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", + (unsigned int)p->hdr.pkt_type, p->name)); + break; + case RPC_BIND: /* * We assume that a pipe bind is only in one pdu. @@ -724,6 +750,14 @@ static void process_complete_pdu(pipes_struct *p) reply = api_pipe_bind_req(p, &rpc_in); } break; + + case RPC_BINDACK: + case RPC_BINDNACK: + DEBUG(0,("process_complete_pdu: Error. RPC_BINDACK/RPC_BINDNACK packet type %u received on pipe %s.\n", + (unsigned int)p->hdr.pkt_type, p->name)); + break; + + case RPC_ALTCONT: /* * We assume that a pipe bind is only in one pdu. @@ -732,6 +766,12 @@ static void process_complete_pdu(pipes_struct *p) reply = api_pipe_alter_context(p, &rpc_in); } break; + + case RPC_ALTCONTRESP: + DEBUG(0,("process_complete_pdu: Error. RPC_ALTCONTRESP on pipe %s: Should only be server -> client.\n", + p->name)); + break; + case RPC_AUTH3: /* * The third packet in an NTLMSSP auth exchange. @@ -740,9 +780,38 @@ static void process_complete_pdu(pipes_struct *p) reply = api_pipe_bind_auth3(p, &rpc_in); } break; - case RPC_REQUEST: - reply = process_request_pdu(p, &rpc_in); + + case RPC_SHUTDOWN: + DEBUG(0,("process_complete_pdu: Error. RPC_SHUTDOWN on pipe %s: Should only be server -> client.\n", + p->name)); + break; + + case RPC_CO_CANCEL: + /* For now just free all client data and continue processing. */ + DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n")); + /* As we never do asynchronous RPC serving, we can never cancel a + call (as far as I know). If we ever did we'd have to send a cancel_ack + reply. For now, just free all client data and continue processing. */ + reply = True; break; +#if 0 + /* Enable this if we're doing async rpc. */ + /* We must check the call-id matches the outstanding callid. */ + if(pipe_init_outgoing_data(p)) { + /* Send a cancel_ack PDU reply. */ + /* We should probably check the auth-verifier here. */ + reply = setup_cancel_ack_reply(p, &rpc_in); + } + break; +#endif + + case RPC_ORPHANED: + /* We should probably check the auth-verifier here. + For now just free all client data and continue processing. */ + DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n")); + reply = True; + break; + default: DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type )); break; @@ -815,7 +884,13 @@ incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned */ if(p->in_data.pdu_needed_len == 0) { - return unmarshall_rpc_header(p); + ssize_t rret = unmarshall_rpc_header(p); + if (rret == -1 || p->in_data.pdu_needed_len > 0) { + return rret; + } + /* If rret == 0 and pdu_needed_len == 0 here we have a PDU that consists + of an RPC_HEADER only. This is a RPC_SHUTDOWN, RPC_CO_CANCEL or RPC_ORPHANED + pdu type. Deal with this in process_complete_pdu(). */ } /* |