diff options
-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(). */ } /* |