From bb6af711b8f9a525b74198abbe7f1c37014ca6f7 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 20 Jan 2002 02:40:05 +0000 Subject: This is the current patch from Luke Leighton to add a degree of seperation betwen reading/writing the raw NamedPipe SMB packets and the matching operations inside smbd's RPC components. This patch is designed for no change in behaviour, and my tests hold that to be true. This patch does however allow for the future loadable modules interface to specify function pointers in replacement of the fixed state. The pipes_struct has been split into two peices, with smb_np_struct taking the information that should be generic to where the data ends up. Some other minor changes are made: we get another small helper function in util_sock.c and some of the original code has better failure debugs and variable use. (As per on-list comments). Andrew Bartlett (This used to be commit 8ef13cabdddf58b741886782297fb64b2fb7e489) --- source3/rpc_server/srv_lsa_hnd.c | 4 +- source3/rpc_server/srv_pipe_hnd.c | 264 ++++++++++++++++++++++++++++-------- source3/rpc_server/srv_spoolss_nt.c | 2 +- 3 files changed, 210 insertions(+), 60 deletions(-) (limited to 'source3/rpc_server') diff --git a/source3/rpc_server/srv_lsa_hnd.c b/source3/rpc_server/srv_lsa_hnd.c index d5f9a52e2f..e4a00443a1 100644 --- a/source3/rpc_server/srv_lsa_hnd.c +++ b/source3/rpc_server/srv_lsa_hnd.c @@ -35,10 +35,10 @@ BOOL init_pipe_handle_list(pipes_struct *p, char *pipe_name) { - pipes_struct *plist = get_first_pipe(); + pipes_struct *plist = get_first_internal_pipe(); struct handle_list *hl = NULL; - for (plist = get_first_pipe(); plist; plist = get_next_pipe(plist)) { + for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist)) { if (strequal( plist->name, pipe_name)) { if (!plist->pipe_handles) { pstring msg; diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index cc6415cce7..a98bcdc6bb 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -26,26 +26,58 @@ #define PIPE "\\PIPE\\" #define PIPELEN strlen(PIPE) -static pipes_struct *chain_p; +static smb_np_struct *chain_p; static int pipes_open; #ifndef MAX_OPEN_PIPES #define MAX_OPEN_PIPES 2048 #endif -static pipes_struct *Pipes; +static smb_np_struct *Pipes; +static pipes_struct *InternalPipes; static struct bitmap *bmap; +/* TODO + * the following prototypes are declared here to avoid + * code being moved about too much for a patch to be + * disrupted / less obvious. + * + * these functions, and associated functions that they + * call, should be moved behind a .so module-loading + * system _anyway_. so that's the next step... + */ + +static ssize_t read_from_internal_pipe(void *np_conn, char *data, size_t n, + BOOL *is_data_outstanding); +static ssize_t write_to_internal_pipe(void *np_conn, char *data, size_t n); +static BOOL close_internal_rpc_pipe_hnd(void *np_conn); +static void *make_internal_rpc_pipe_p(char *pipe_name, + connection_struct *conn, uint16 vuid); + /**************************************************************************** Pipe iterator functions. ****************************************************************************/ -pipes_struct *get_first_pipe(void) +smb_np_struct *get_first_pipe(void) { return Pipes; } -pipes_struct *get_next_pipe(pipes_struct *p) +smb_np_struct *get_next_pipe(smb_np_struct *p) +{ + return p->next; +} + +/**************************************************************************** + Internal Pipe iterator functions. +****************************************************************************/ + +pipes_struct *get_first_internal_pipe(void) +{ + return InternalPipes; +} + +pipes_struct *get_next_internal_pipe(pipes_struct *p) { return p->next; } @@ -118,11 +150,11 @@ static BOOL pipe_init_outgoing_data(pipes_struct *p) Find first available pipe slot. ****************************************************************************/ -pipes_struct *open_rpc_pipe_p(char *pipe_name, +smb_np_struct *open_rpc_pipe_p(char *pipe_name, connection_struct *conn, uint16 vuid) { int i; - pipes_struct *p; + smb_np_struct *p, *p_it; static int next_pipe; DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n", @@ -147,22 +179,28 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, for (p = Pipes; p; p = p->next) DEBUG(5,("open_rpc_pipe_p: name %s pnum=%x\n", p->name, p->pnum)); - p = (pipes_struct *)malloc(sizeof(*p)); + p = (smb_np_struct *)malloc(sizeof(*p)); if (!p) + { + DEBUG(0,("ERROR! no memory for pipes_struct!\n")); return NULL; + } ZERO_STRUCTP(p); - if ((p->mem_ctx = talloc_init()) == NULL) { - DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n")); - SAFE_FREE(p); - return NULL; - } + /* add a dso mechanism instead of this, here */ - if (!init_pipe_handle_list(p, pipe_name)) { - DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n")); - talloc_destroy(p->mem_ctx); + p->namedpipe_create = make_internal_rpc_pipe_p; + p->namedpipe_read = read_from_internal_pipe; + p->namedpipe_write = write_to_internal_pipe; + p->namedpipe_close = close_internal_rpc_pipe_hnd; + + p->np_state = p->namedpipe_create(pipe_name, conn, vuid); + + if (p->np_state == NULL) { + + DEBUG(0,("open_rpc_pipe_p: make_internal_rpc_pipe_p failed.\n")); SAFE_FREE(p); return NULL; } @@ -177,11 +215,6 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, * change the type to UNMARSALLING before processing the stream. */ - if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) { - DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); - return NULL; - } - bitmap_set(bmap, i); i += pipe_handle_offset; @@ -197,6 +230,71 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, p->max_trans_reply = 0; + fstrcpy(p->name, pipe_name); + + DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n", + pipe_name, i, pipes_open)); + + chain_p = p; + + /* Iterate over p_it as a temp variable, to display all open pipes */ + for (p_it = Pipes; p_it; p_it = p_it->next) + DEBUG(5,("open pipes: name %s pnum=%x\n", p_it->name, p_it->pnum)); + + return chain_p; +} + +/**************************************************************************** + * make an internal namedpipes structure +****************************************************************************/ + +static void *make_internal_rpc_pipe_p(char *pipe_name, + connection_struct *conn, uint16 vuid) +{ + pipes_struct *p; + + DEBUG(4,("Create pipe requested %s\n", pipe_name)); + + p = (pipes_struct *)malloc(sizeof(*p)); + + if (!p) + { + DEBUG(0,("ERROR! no memory for pipes_struct!\n")); + return NULL; + } + + ZERO_STRUCTP(p); + + if ((p->mem_ctx = talloc_init()) == NULL) { + DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n")); + SAFE_FREE(p); + return NULL; + } + + if (!init_pipe_handle_list(p, pipe_name)) { + DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n")); + talloc_destroy(p->mem_ctx); + SAFE_FREE(p); + return NULL; + } + + /* + * 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, p->mem_ctx, MARSHALL)) { + DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); + return NULL; + } + + DLIST_ADD(InternalPipes, p); + + p->conn = conn; + p->vuid = vuid; + p->ntlmssp_chal_flags = 0; p->ntlmssp_auth_validated = False; p->ntlmssp_auth_requested = False; @@ -205,6 +303,11 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, p->fault_state = False; p->endian = RPC_LITTLE_ENDIAN; + ZERO_STRUCT(p->pipe_user); + + p->pipe_user.uid = (uid_t)-1; + p->pipe_user.gid = (gid_t)-1; + /* * Initialize the incoming RPC struct. */ @@ -225,23 +328,12 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, */ prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL); - ZERO_STRUCT(p->pipe_user); - - p->pipe_user.uid = (uid_t)-1; - p->pipe_user.gid = (gid_t)-1; - fstrcpy(p->name, pipe_name); - DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n", - pipe_name, i, pipes_open)); - - chain_p = p; - - /* OVERWRITE p as a temp variable, to display all open pipes */ - for (p = Pipes; p; p = p->next) - DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum)); + DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n", + pipe_name, pipes_open)); - return chain_p; + return (void*)p; } /**************************************************************************** @@ -254,8 +346,8 @@ static void set_incoming_fault(pipes_struct *p) 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 )); + DEBUG(10,("set_incoming_fault: Setting fault state on pipe %s : vuid = 0x%x\n", + p->name, p->vuid )); } /**************************************************************************** @@ -712,10 +804,8 @@ incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned Accepts incoming data on an rpc pipe. ****************************************************************************/ -ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n) +ssize_t write_to_pipe(smb_np_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\n", @@ -723,6 +813,18 @@ ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n) dump_data(50, data, n); + return p->namedpipe_write(p->np_state, data, n); +} + +/**************************************************************************** + Accepts incoming data on an internal rpc pipe. +****************************************************************************/ + +static ssize_t write_to_internal_pipe(void *np_conn, char *data, size_t n) +{ + pipes_struct *p = (pipes_struct*)np_conn; + size_t data_left = n; + while(data_left) { ssize_t data_used; @@ -753,11 +855,9 @@ ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n) have been prepared into arrays of headers + data stream sections. ****************************************************************************/ -ssize_t read_from_pipe(pipes_struct *p, char *data, size_t n) +ssize_t read_from_pipe(smb_np_struct *p, char *data, size_t n, + BOOL *is_data_outstanding) { - uint32 pdu_remaining = 0; - ssize_t data_returned = 0; - if (!p || !p->open) { DEBUG(0,("read_from_pipe: pipe not open\n")); return -1; @@ -765,6 +865,32 @@ ssize_t read_from_pipe(pipes_struct *p, char *data, size_t n) DEBUG(6,("read_from_pipe: %x", p->pnum)); + return p->namedpipe_read(p->np_state, data, n, is_data_outstanding); +} + +/**************************************************************************** + Replies to a request to read data from a pipe. + + Headers are interspersed with the data at PDU intervals. By the time + this function is called, the start of the data could possibly have been + read by an SMBtrans (file_offset != 0). + + Calling create_rpc_reply() here is a hack. The data should already + have been prepared into arrays of headers + data stream sections. +****************************************************************************/ + +static ssize_t read_from_internal_pipe(void *np_conn, char *data, size_t n, + BOOL *is_data_outstanding) +{ + pipes_struct *p = (pipes_struct*)np_conn; + uint32 pdu_remaining = 0; + ssize_t data_returned = 0; + + if (!p) { + DEBUG(0,("read_from_pipe: pipe not open\n")); + return -1; + } + DEBUG(6,(" name: %s len: %u\n", p->name, (unsigned int)n)); /* @@ -839,6 +965,7 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len, out: + (*is_data_outstanding) = p->out_data.current_pdu_len > n; return data_returned; } @@ -846,7 +973,7 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len, Wait device state on a pipe. Exactly what this is for is unknown... ****************************************************************************/ -BOOL wait_rpc_pipe_hnd_state(pipes_struct *p, uint16 priority) +BOOL wait_rpc_pipe_hnd_state(smb_np_struct *p, uint16 priority) { if (p == NULL) return False; @@ -870,7 +997,7 @@ BOOL wait_rpc_pipe_hnd_state(pipes_struct *p, uint16 priority) Set device state on a pipe. Exactly what this is for is unknown... ****************************************************************************/ -BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state) +BOOL set_rpc_pipe_hnd_state(smb_np_struct *p, uint16 device_state) { if (p == NULL) return False; @@ -894,21 +1021,14 @@ BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state) Close an rpc pipe. ****************************************************************************/ -BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) +BOOL close_rpc_pipe_hnd(smb_np_struct *p) { if (!p) { DEBUG(0,("Invalid pipe in close_rpc_pipe_hnd\n")); return False; } - prs_mem_free(&p->out_data.rdata); - prs_mem_free(&p->in_data.data); - - if (p->mem_ctx) - talloc_destroy(p->mem_ctx); - - /* Free the handles database. */ - close_policy_by_pipe(p); + p->namedpipe_close(p->np_state); bitmap_clear(bmap, p->pnum - pipe_handle_offset); @@ -919,9 +1039,39 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) DLIST_REMOVE(Pipes, p); + ZERO_STRUCTP(p); + + SAFE_FREE(p); + + return True; +} + +/**************************************************************************** + Close an rpc pipe. +****************************************************************************/ + +static BOOL close_internal_rpc_pipe_hnd(void *np_conn) +{ + pipes_struct *p = (pipes_struct *)np_conn; + if (!p) { + DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n")); + return False; + } + + prs_mem_free(&p->out_data.rdata); + prs_mem_free(&p->in_data.data); + + if (p->mem_ctx) + talloc_destroy(p->mem_ctx); + + /* Free the handles database. */ + close_policy_by_pipe(p); + delete_nt_token(&p->pipe_user.nt_user_token); SAFE_FREE(p->pipe_user.groups); + DLIST_REMOVE(InternalPipes, p); + ZERO_STRUCTP(p); SAFE_FREE(p); @@ -933,7 +1083,7 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) Find an rpc pipe given a pipe handle in a buffer and an offset. ****************************************************************************/ -pipes_struct *get_rpc_pipe_p(char *buf, int where) +smb_np_struct *get_rpc_pipe_p(char *buf, int where) { int pnum = SVAL(buf,where); @@ -947,9 +1097,9 @@ pipes_struct *get_rpc_pipe_p(char *buf, int where) Find an rpc pipe given a pipe handle. ****************************************************************************/ -pipes_struct *get_rpc_pipe(int pnum) +smb_np_struct *get_rpc_pipe(int pnum) { - pipes_struct *p; + smb_np_struct *p; DEBUG(4,("search for pipe pnum=%x\n", pnum)); diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 2b41efcbf6..bdd2bbf31b 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -633,7 +633,7 @@ static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size */ hl = NULL; - for ( p = get_first_pipe(); p; p = get_next_pipe(p)) { + for ( p = get_first_internal_pipe(); p; get_next_internal_pipe(p)) { if (strequal(p->name, "spoolss")) { hl = p->pipe_handles; break; -- cgit