📄 srv_pipe_hnd.c
字号:
/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-1998, * Largely re-written : 2005 * Copyright (C) Jeremy Allison 1998 - 2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "includes.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_RPC_SRV#define PIPE "\\PIPE\\"#define PIPELEN strlen(PIPE)static smb_np_struct *chain_p;static int pipes_open;/* * Sometimes I can't decide if I hate Windows printer driver * writers more than I hate the Windows spooler service driver * writers. This gets around a combination of bugs in the spooler * and the HP 8500 PCL driver that causes a spooler spin. JRA. * * bumped up from 20 -> 64 after viewing traffic from WordPerfect * 2002 running on NT 4.- SP6 * bumped up from 64 -> 256 after viewing traffic from con2prt * for lots of printers on a WinNT 4.x SP6 box. */ #ifndef MAX_OPEN_SPOOLSS_PIPES#define MAX_OPEN_SPOOLSS_PIPES 256#endifstatic int current_spoolss_pipes_open;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.****************************************************************************/smb_np_struct *get_first_pipe(void){ return Pipes;}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;}/* this must be larger than the sum of the open files and directories */static int pipe_handle_offset;/**************************************************************************** Set the pipe_handle_offset. Called from smbd/files.c****************************************************************************/void set_pipe_handle_offset(int max_open_files){ if(max_open_files < 0x7000) { pipe_handle_offset = 0x7000; } else { pipe_handle_offset = max_open_files + 10; /* For safety. :-) */ }}/**************************************************************************** Reset pipe chain handle number.****************************************************************************/void reset_chain_p(void){ chain_p = NULL;}/**************************************************************************** Initialise pipe handle states.****************************************************************************/void init_rpc_pipe_hnd(void){ bmap = bitmap_allocate(MAX_OPEN_PIPES); if (!bmap) { exit_server("out of memory in init_rpc_pipe_hnd"); }}/**************************************************************************** Initialise an outgoing packet.****************************************************************************/static BOOL pipe_init_outgoing_data(pipes_struct *p){ output_data *o_data = &p->out_data; /* Reset the offset counters. */ o_data->data_sent_length = 0; o_data->current_pdu_len = 0; o_data->current_pdu_sent = 0; memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu)); /* Free any memory in the current return data buffer. */ 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(&o_data->rdata, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) { DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n")); return False; } return True;}/**************************************************************************** Find first available pipe slot.****************************************************************************/smb_np_struct *open_rpc_pipe_p(char *pipe_name, connection_struct *conn, uint16 vuid){ int i; smb_np_struct *p, *p_it; static int next_pipe; BOOL is_spoolss_pipe = False; DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n", pipe_name, pipes_open)); if (strstr(pipe_name, "spoolss")) { is_spoolss_pipe = True; } if (is_spoolss_pipe && current_spoolss_pipes_open >= MAX_OPEN_SPOOLSS_PIPES) { DEBUG(10,("open_rpc_pipe_p: spooler bug workaround. Denying open on pipe %s\n", pipe_name )); return NULL; } /* 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 */ if (next_pipe == 0) { next_pipe = (sys_getpid() ^ time(NULL)) % MAX_OPEN_PIPES; } i = bitmap_find(bmap, next_pipe); if (i == -1) { DEBUG(0,("ERROR! Out of pipe structures\n")); return NULL; } next_pipe = (i+1) % MAX_OPEN_PIPES; for (p = Pipes; p; p = p->next) { DEBUG(5,("open_rpc_pipe_p: name %s pnum=%x\n", p->name, p->pnum)); } p = SMB_MALLOC_P(smb_np_struct); if (!p) { DEBUG(0,("ERROR! no memory for pipes_struct!\n")); return NULL; } ZERO_STRUCTP(p); /* add a dso mechanism instead of this, here */ 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; } 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. */ bitmap_set(bmap, i); i += pipe_handle_offset; pipes_open++; p->pnum = i; p->open = True; p->device_state = 0; p->priority = 0; p->conn = conn; p->vuid = vuid; 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; user_struct *vuser = get_valid_user_struct(vuid); DEBUG(4,("Create pipe requested %s\n", pipe_name)); if (!vuser && vuid != UID_FIELD_INVALID) { DEBUG(0,("ERROR! vuid %d did not map to a valid vuser struct!\n", vuid)); return NULL; } p = SMB_MALLOC_P(pipes_struct); if (!p) { DEBUG(0,("ERROR! no memory for pipes_struct!\n")); return NULL; } ZERO_STRUCTP(p); if ((p->mem_ctx = talloc_init("pipe %s %p", pipe_name, p)) == NULL) { DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n")); SAFE_FREE(p); return NULL; } if ((p->pipe_state_mem_ctx = talloc_init("pipe_state %s %p", pipe_name, p)) == NULL) { DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n")); talloc_destroy(p->mem_ctx); 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); talloc_destroy(p->pipe_state_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, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) { DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); talloc_destroy(p->mem_ctx); talloc_destroy(p->pipe_state_mem_ctx); return NULL; } DLIST_ADD(InternalPipes, p); p->conn = conn; p->vuid = vuid; p->endian = RPC_LITTLE_ENDIAN; ZERO_STRUCT(p->pipe_user); p->pipe_user.uid = (uid_t)-1; p->pipe_user.gid = (gid_t)-1; /* Store the session key and NT_TOKEN */ if (vuser) { p->session_key = data_blob(vuser->session_key.data, vuser->session_key.length); p->pipe_user.nt_user_token = dup_nt_token(vuser->nt_user_token); } /* * Initialize the outgoing RPC data buffer with no memory. */ prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL); fstrcpy(p->name, pipe_name); DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n", pipe_name, pipes_open)); return (void*)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 : vuid = 0x%x\n", p->name, p->vuid ));}/**************************************************************************** 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, p->mem_ctx, UNMARSHALL); prs_set_endian_data( &rpc_in, p->endian); 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -