📄 rpc_transport.c
字号:
/* * RPC transport layer * * Copyright 2001 Ove K鍁en, TransGaming Technologies * Copyright 2003 Mike Hearn * Copyright 2004 Filip Navara * Copyright 2006 Mike McCormack * Copyright 2006 Damjan Jovanovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */#include "config.h"#include <stdarg.h>#include <stdio.h>#include <string.h>#include <assert.h>#include <errno.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include <stdlib.h>#include <sys/types.h>#ifdef HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H# include <netinet/in.h>#endif#ifdef HAVE_NETINET_TCP_H# include <netinet/tcp.h>#endif#ifdef HAVE_ARPA_INET_H# include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_SYS_POLL_H#include <sys/poll.h>#endif#include <winsock2.h>#include <ws2tcpip.h>#include "windef.h"#include "winbase.h"#include "winnls.h"#include "winerror.h"#include "winternl.h"#include "wine/unicode.h"#include "rpc.h"#include "rpcndr.h"#include "wine/debug.h"#include "rpc_binding.h"#include "rpc_message.h"#include "rpc_server.h"#include "epm_towers.h"#include "unix_func.h"#ifndef SOL_TCP# define SOL_TCP IPPROTO_TCP#endifWINE_DEFAULT_DEBUG_CHANNEL(rpc);static CRITICAL_SECTION assoc_list_cs;static CRITICAL_SECTION_DEBUG assoc_list_cs_debug ={ 0, 0, &assoc_list_cs, { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }};static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };static struct list assoc_list = LIST_INIT(assoc_list);/**** ncacn_np support ****/typedef struct _RpcConnection_np{ RpcConnection common; HANDLE pipe; OVERLAPPED ovl; BOOL listening;} RpcConnection_np;static RpcConnection *rpcrt4_conn_np_alloc(void){ RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np)); if (npc) { npc->pipe = NULL; memset(&npc->ovl, 0, sizeof(npc->ovl)); npc->listening = FALSE; } return &npc->common;}static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc){ if (npc->listening) return RPC_S_OK; npc->listening = TRUE; if (ConnectNamedPipe(npc->pipe, &npc->ovl)) return RPC_S_OK; if (GetLastError() == ERROR_PIPE_CONNECTED) { SetEvent(npc->ovl.hEvent); return RPC_S_OK; } if (GetLastError() == ERROR_IO_PENDING) { /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */ return RPC_S_OK; } npc->listening = FALSE; WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError()); return RPC_S_OUT_OF_RESOURCES;}static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname){ RpcConnection_np *npc = (RpcConnection_np *) Connection; TRACE("listening on %s\n", pname); npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); if (npc->pipe == INVALID_HANDLE_VALUE) { WARN("CreateNamedPipe failed with error %d\n", GetLastError()); if (GetLastError() == ERROR_FILE_EXISTS) return RPC_S_DUPLICATE_ENDPOINT; else return RPC_S_CANT_CREATE_ENDPOINT; } memset(&npc->ovl, 0, sizeof(npc->ovl)); npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); /* Note: we don't call ConnectNamedPipe here because it must be done in the * server thread as the thread must be alertable */ return RPC_S_OK;}static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait){ RpcConnection_np *npc = (RpcConnection_np *) Connection; HANDLE pipe; DWORD err, dwMode; TRACE("connecting to %s\n", pname); while (TRUE) { DWORD dwFlags = 0; if (Connection->QOS) { dwFlags = SECURITY_SQOS_PRESENT; switch (Connection->QOS->qos->ImpersonationType) { case RPC_C_IMP_LEVEL_DEFAULT: /* FIXME: what to do here? */ break; case RPC_C_IMP_LEVEL_ANONYMOUS: dwFlags |= SECURITY_ANONYMOUS; break; case RPC_C_IMP_LEVEL_IDENTIFY: dwFlags |= SECURITY_IDENTIFICATION; break; case RPC_C_IMP_LEVEL_IMPERSONATE: dwFlags |= SECURITY_IMPERSONATION; break; case RPC_C_IMP_LEVEL_DELEGATE: dwFlags |= SECURITY_DELEGATION; break; } if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC) dwFlags |= SECURITY_CONTEXT_TRACKING; } pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, dwFlags, 0); if (pipe != INVALID_HANDLE_VALUE) break; err = GetLastError(); if (err == ERROR_PIPE_BUSY) { TRACE("connection failed, error=%x\n", err); return RPC_S_SERVER_TOO_BUSY; } if (!wait) return RPC_S_SERVER_UNAVAILABLE; if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { err = GetLastError(); WARN("connection failed, error=%x\n", err); return RPC_S_SERVER_UNAVAILABLE; } } /* success */ memset(&npc->ovl, 0, sizeof(npc->ovl)); /* pipe is connected; change to message-read mode. */ dwMode = PIPE_READMODE_MESSAGE; SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL); npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); npc->pipe = pipe; return RPC_S_OK;}static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection){ RpcConnection_np *npc = (RpcConnection_np *) Connection; static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; RPC_STATUS r; LPSTR pname; /* already connected? */ if (npc->pipe) return RPC_S_OK; /* protseq=ncalrpc: supposed to use NT LPC ports, * but we'll implement it with named pipes for now */ pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); strcat(strcpy(pname, prefix), Connection->Endpoint); r = rpcrt4_conn_open_pipe(Connection, pname, TRUE); I_RpcFree(pname); return r;}static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint){ static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; RPC_STATUS r; LPSTR pname; RpcConnection *Connection; r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, endpoint, NULL, NULL, NULL); if (r != RPC_S_OK) return r; /* protseq=ncalrpc: supposed to use NT LPC ports, * but we'll implement it with named pipes for now */ pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); strcat(strcpy(pname, prefix), Connection->Endpoint); r = rpcrt4_conn_create_pipe(Connection, pname); I_RpcFree(pname); EnterCriticalSection(&protseq->cs); Connection->Next = protseq->conn; protseq->conn = Connection; LeaveCriticalSection(&protseq->cs); return r;}static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection){ RpcConnection_np *npc = (RpcConnection_np *) Connection; static const char prefix[] = "\\\\."; RPC_STATUS r; LPSTR pname; /* already connected? */ if (npc->pipe) return RPC_S_OK; /* protseq=ncacn_np: named pipes */ pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); strcat(strcpy(pname, prefix), Connection->Endpoint); r = rpcrt4_conn_open_pipe(Connection, pname, FALSE); I_RpcFree(pname); return r;}static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint){ static const char prefix[] = "\\\\."; RPC_STATUS r; LPSTR pname; RpcConnection *Connection; r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, endpoint, NULL, NULL, NULL); if (r != RPC_S_OK) return r; /* protseq=ncacn_np: named pipes */ pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); strcat(strcpy(pname, prefix), Connection->Endpoint); r = rpcrt4_conn_create_pipe(Connection, pname); I_RpcFree(pname); EnterCriticalSection(&protseq->cs); Connection->Next = protseq->conn; protseq->conn = Connection; LeaveCriticalSection(&protseq->cs); return r;}static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc){ /* because of the way named pipes work, we'll transfer the connected pipe * to the child, then reopen the server binding to continue listening */ new_npc->pipe = old_npc->pipe; new_npc->ovl = old_npc->ovl; old_npc->pipe = 0; memset(&old_npc->ovl, 0, sizeof(old_npc->ovl)); old_npc->listening = FALSE;}static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn){ RPC_STATUS status; LPSTR pname; static const char prefix[] = "\\\\."; rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); strcat(strcpy(pname, prefix), old_conn->Endpoint); status = rpcrt4_conn_create_pipe(old_conn, pname); I_RpcFree(pname); return status;}static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn){ RPC_STATUS status; LPSTR pname; static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; TRACE("%s\n", old_conn->Endpoint); rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); strcat(strcpy(pname, prefix), old_conn->Endpoint); status = rpcrt4_conn_create_pipe(old_conn, pname); I_RpcFree(pname); return status;}static int rpcrt4_conn_np_read(RpcConnection *Connection, void *buffer, unsigned int count){ RpcConnection_np *npc = (RpcConnection_np *) Connection; char *buf = buffer; BOOL ret = TRUE; unsigned int bytes_left = count; while (bytes_left) { DWORD bytes_read; ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL); if (!ret || !bytes_read) break; bytes_left -= bytes_read; buf += bytes_read; } return ret ? count : -1;}static int rpcrt4_conn_np_write(RpcConnection *Connection, const void *buffer, unsigned int count){ RpcConnection_np *npc = (RpcConnection_np *) Connection; const char *buf = buffer; BOOL ret = TRUE; unsigned int bytes_left = count; while (bytes_left) { DWORD bytes_written; ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL); if (!ret || !bytes_written) break; bytes_left -= bytes_written; buf += bytes_written; } return ret ? count : -1;}static int rpcrt4_conn_np_close(RpcConnection *Connection){ RpcConnection_np *npc = (RpcConnection_np *) Connection; if (npc->pipe) { FlushFileBuffers(npc->pipe); CloseHandle(npc->pipe); npc->pipe = 0; } if (npc->ovl.hEvent) { CloseHandle(npc->ovl.hEvent); npc->ovl.hEvent = 0; } return 0;}static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data, const char *networkaddr, const char *endpoint){ twr_empty_floor_t *smb_floor; twr_empty_floor_t *nb_floor; size_t size; size_t networkaddr_size; size_t endpoint_size; TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); networkaddr_size = strlen(networkaddr) + 1; endpoint_size = strlen(endpoint) + 1; size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size; if (!tower_data) return size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -