diff --git a/.gitignore b/.gitignore index d546c2e0c9a..4d8443a2402 100644 --- a/.gitignore +++ b/.gitignore @@ -549,6 +549,8 @@ include/unknwn.h include/urlhist.h include/urlmon.h include/vmr9.h +include/wine/dcetypes.h +include/wine/epm.h include/wine/itss.h include/wine/svcctl.h include/wtypes.h @@ -590,6 +592,8 @@ programs/progman/progman programs/reg/reg programs/regedit/regedit programs/regsvr32/regsvr32 +programs/rpcss/epm.h +programs/rpcss/epm_s.c programs/rpcss/irot.h programs/rpcss/irot_s.c programs/rpcss/rpcss diff --git a/include/Makefile.in b/include/Makefile.in index c38d27cc4e4..54747a6f9be 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -68,6 +68,8 @@ IDL_H_SRCS = \ urlhist.idl \ urlmon.idl \ vmr9.idl \ + wine/dcetypes.idl \ + wine/epm.idl \ wine/itss.idl \ wine/svcctl.idl \ wtypes.idl \ diff --git a/include/wine/dcetypes.idl b/include/wine/dcetypes.idl new file mode 100644 index 00000000000..8bfbb09e386 --- /dev/null +++ b/include/wine/dcetypes.idl @@ -0,0 +1,88 @@ +/* + * Common DCE Types + * + * Copyright 2006 Robert Shearman (for CodeWeavers) + * + * 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 + */ + +/* pull in GUID type */ +import "wtypes.idl"; + +typedef unsigned small unsigned8; +typedef unsigned short unsigned16; +typedef unsigned long unsigned32; +typedef small signed8; +typedef short signed16; +typedef long signed32; +typedef unsigned32 boolean32; +typedef unsigned hyper u_int64; +typedef unsigned long u_int32; +typedef unsigned short u_int16; +typedef unsigned small u_int8; + +typedef [ptr] GUID *uuid_p_t; + +typedef struct twr_t +{ + unsigned32 tower_length; + [size_is(tower_length)] byte tower_octet_string[]; +} twr_t; +typedef [ptr] twr_t *twr_p_t; + +typedef struct ndr_context_handle +{ + unsigned32 context_handle_attributes; + GUID context_handle_uuid; +} ndr_context_handle; + +const long ndr_c_int_big_endian = 0; +const long ndr_c_int_little_endian = 1; +const long ndr_c_float_ieee = 0; +const long ndr_c_float_vax = 1; +const long ndr_c_float_cray = 2; +const long ndr_c_float_ibm = 3; +const long ndr_c_char_ascii = 0; +const long ndr_c_char_ebcdic = 1; + +typedef struct +{ + unsigned8 int_rep; + unsigned8 char_rep; + unsigned8 float_rep; + byte reserved; +} ndr_format_t, *ndr_format_p_t; + +typedef struct +{ + GUID uuid; + unsigned16 vers_major; + unsigned16 vers_minor; +} rpc_if_id_t; +typedef [unique] rpc_if_id_t *rpc_if_id_p_t; + +typedef struct +{ + unsigned32 count; + [size_is(count)] + rpc_if_id_p_t if_id[*]; +} rpc_if_id_vector_t; +typedef [unique] rpc_if_id_vector_t *rpc_if_id_vector_p_t; + +typedef struct +{ + unsigned32 count; + unsigned32 stats[1]; /* length_is (count) */ +} rpc_stats_vector_t, *rpc_stats_vector_p_t; diff --git a/include/wine/epm.idl b/include/wine/epm.idl new file mode 100644 index 00000000000..301deb6810a --- /dev/null +++ b/include/wine/epm.idl @@ -0,0 +1,122 @@ +/* + * Endpoint Mapper + * + * Copyright 2006 Robert Shearman (for CodeWeavers) + * + * 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 + */ + +/* FIXME: should be import */ +#include "dcetypes.idl" + +cpp_quote("RPC_STATUS WINAPI TowerExplode(") +cpp_quote(" const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax,") +cpp_quote(" char **protseq, char **endpoint, char **address);") +cpp_quote("RPC_STATUS WINAPI TowerConstruct(") +cpp_quote(" const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax,") +cpp_quote(" const char *protseq, const char *endpoint, const char *address,") +cpp_quote(" twr_t **tower);") + +[ + uuid(e1af8308-5d1f-11c9-91a4-08002b14a0fa), + version(3.0), + pointer_default(ref) +] +interface epm +{ + const long ept_max_annotation_size = 64; + + typedef struct + { + GUID object; + twr_t *tower; + [string] char annotation[ept_max_annotation_size]; + } ept_entry_t, *ept_entry_p_t; + + typedef [context_handle] void *ept_lookup_handle_t; + + /* Adds entries to an endpoint map */ + void ept_insert( + [in] handle_t h, + [in] unsigned32 num_ents, + [in, size_is(num_ents)] + ept_entry_t entries[], + [in] boolean32 replace, + [out] error_status_t *status + ); + + /* Removes entries from an endpoint map */ + void ept_delete( + [in] handle_t h, + [in] unsigned32 num_ents, + [in, size_is(num_ents)] + ept_entry_t entries[], + [out] error_status_t *status + ); + + /* Lookup entries in an endpoint map */ + [idempotent] + void ept_lookup( + [in] handle_t h, + [in] unsigned32 inquiry_type, + [in] uuid_p_t object, + [in] rpc_if_id_p_t interface_id, + [in] unsigned32 vers_option, + [in, out] ept_lookup_handle_t *entry_handle, + [in] unsigned32 max_ents, + [out] unsigned32 *num_ents, + [out, length_is(*num_ents), size_is(max_ents)] + ept_entry_t entries[], + [out] error_status_t *status + ); + + /* Lookup entries in an endpoint map using the given input pattern */ + [idempotent] + void ept_map( + [in] handle_t h, + [in] uuid_p_t object, + [in] twr_p_t map_tower, + [in, out] ept_lookup_handle_t *entry_handle, + [in] unsigned32 max_towers, + [out] unsigned32 *num_towers, + [out, length_is(*num_towers), size_is(max_towers)] + twr_p_t *towers, + [out] error_status_t *status + ); + + /* Free the context handle returned by ept_lookup or ept_map */ + void ept_lookup_handle_free( + [in] handle_t h, + [in, out] ept_lookup_handle_t *entry_handle, + [out] error_status_t *status + ); + + /* Inquires as to the endpoint map's object identifier */ + [idempotent] + void ept_inq_object( + [in] handle_t h, + [out] GUID *ept_object, + [out] error_status_t *status + ); + + /* Deletes matching entries in the endpoint map */ + void ept_mgmt_delete( + [in] handle_t h, + [in] boolean32 object_speced, + [in] uuid_p_t object, + [in] twr_p_t tower, + [out] error_status_t *status + ); +} diff --git a/programs/rpcss/Makefile.in b/programs/rpcss/Makefile.in index 7a991a9a8fd..2f621bae33b 100644 --- a/programs/rpcss/Makefile.in +++ b/programs/rpcss/Makefile.in @@ -8,11 +8,13 @@ IMPORTS = rpcrt4 kernel32 ntdll C_SRCS = \ epmap_server.c \ + epmp.c \ irotp.c \ np_server.c \ rpcss_main.c IDL_S_SRCS = \ + epm.idl \ irot.idl @MAKE_PROG_RULES@ diff --git a/programs/rpcss/epm.idl b/programs/rpcss/epm.idl new file mode 100644 index 00000000000..67fad348c88 --- /dev/null +++ b/programs/rpcss/epm.idl @@ -0,0 +1,19 @@ +/* + * Copyright 2008 Robert Shearman + * + * 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 "wine/epm.idl" diff --git a/programs/rpcss/epmp.c b/programs/rpcss/epmp.c new file mode 100644 index 00000000000..cf14be8c3d7 --- /dev/null +++ b/programs/rpcss/epmp.c @@ -0,0 +1,283 @@ +/* + * Endpoint Mapper + * + * Copyright (C) 2007 Robert Shearman for CodeWeavers + * + * 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 "epm.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +struct registered_ept_entry +{ + struct list entry; + GUID object; + RPC_SYNTAX_IDENTIFIER iface; + RPC_SYNTAX_IDENTIFIER syntax; + char *protseq; + char *endpoint; + char *address; + char annotation[ept_max_annotation_size]; +}; + +static struct list registered_ept_entry_list = LIST_INIT(registered_ept_entry_list); + +static CRITICAL_SECTION csEpm; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &csEpm, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": csEpm") } +}; +static CRITICAL_SECTION csEpm = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static const UUID nil_object; + +/* must be called inside csEpm */ +static void delete_registered_ept_entry(struct registered_ept_entry *entry) +{ + I_RpcFree(entry->protseq); + I_RpcFree(entry->endpoint); + I_RpcFree(entry->address); + list_remove(&entry->entry); + HeapFree(GetProcessHeap(), 0, entry); +} + +static struct registered_ept_entry *find_ept_entry( + const RPC_SYNTAX_IDENTIFIER *iface, const RPC_SYNTAX_IDENTIFIER *syntax, + const char *protseq, const char *endpoint, const char *address, + const UUID *object) +{ + struct registered_ept_entry *entry; + LIST_FOR_EACH_ENTRY(entry, ®istered_ept_entry_list, struct registered_ept_entry, entry) + { + if (memcmp(&entry->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) continue; + if (memcmp(&entry->syntax, syntax, sizeof(RPC_SYNTAX_IDENTIFIER))) continue; + if (strcmp(entry->protseq, protseq)) continue; + if (memcmp(&entry->object, object, sizeof(UUID))) continue; + WINE_TRACE("found entry with iface %d.%d %s, syntax %d.%d %s, protseq %s, object %s\n", + entry->iface.SyntaxVersion.MajorVersion, entry->iface.SyntaxVersion.MinorVersion, + wine_dbgstr_guid(&entry->iface.SyntaxGUID), + entry->syntax.SyntaxVersion.MajorVersion, entry->syntax.SyntaxVersion.MinorVersion, + wine_dbgstr_guid(&entry->syntax.SyntaxGUID), protseq, + wine_dbgstr_guid(&entry->object)); + return entry; + } + WINE_TRACE("not found\n"); + return NULL; +} + +void __RPC_USER ept_lookup_handle_t_rundown(ept_lookup_handle_t entry_handle) +{ + WINE_FIXME("%p", entry_handle); +} + +void ept_insert(handle_t h, + unsigned32 num_ents, + ept_entry_t entries[], + boolean32 replace, + error_status_t *status) +{ + unsigned32 i; + RPC_STATUS rpc_status; + + WINE_TRACE("(%p, %lu, %p, %lu, %p)\n", h, num_ents, entries, replace, status); + + *status = RPC_S_OK; + + EnterCriticalSection(&csEpm); + + for (i = 0; i < num_ents; i++) + { + struct registered_ept_entry *entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); + if (!entry) + { + /* FIXME: cleanup code to delete added entries */ + *status = EPT_S_CANT_PERFORM_OP; + break; + } + list_init(&entry->entry); + memcpy(entry->annotation, entries[i].annotation, sizeof(entries[i].annotation)); + rpc_status = TowerExplode(entries[i].tower, &entry->iface, &entry->syntax, + &entry->protseq, &entry->endpoint, + &entry->address); + if (rpc_status != RPC_S_OK) + { + *status = rpc_status; + break; /* FIXME: more cleanup? */ + } + + entry->object = entries[i].object; + + if (replace) + { + /* FIXME: correct find algorithm */ + struct registered_ept_entry *old_entry = find_ept_entry(&entry->iface, &entry->syntax, entry->protseq, entry->endpoint, entry->address, &entry->object); + if (old_entry) delete_registered_ept_entry(old_entry); + } + list_add_tail(®istered_ept_entry_list, &entry->entry); + } + + LeaveCriticalSection(&csEpm); +} + +void ept_delete(handle_t h, + unsigned32 num_ents, + ept_entry_t entries[], + error_status_t *status) +{ + unsigned32 i; + RPC_STATUS rpc_status; + + *status = RPC_S_OK; + + WINE_TRACE("(%p, %lu, %p, %p)\n", h, num_ents, entries, status); + + EnterCriticalSection(&csEpm); + + for (i = 0; i < num_ents; i++) + { + struct registered_ept_entry *entry; + RPC_SYNTAX_IDENTIFIER iface, syntax; + char *protseq; + char *endpoint; + char *address; + rpc_status = TowerExplode(entries[i].tower, &iface, &syntax, &protseq, + &endpoint, &address); + if (rpc_status != RPC_S_OK) + break; + entry = find_ept_entry(&iface, &syntax, protseq, endpoint, address, &entries[i].object); + if (entry) + delete_registered_ept_entry(entry); + else + { + *status = EPT_S_NOT_REGISTERED; + break; + } + I_RpcFree(protseq); + I_RpcFree(endpoint); + I_RpcFree(address); + } + + LeaveCriticalSection(&csEpm); +} + +void ept_lookup(handle_t h, + unsigned32 inquiry_type, + uuid_p_t object, + rpc_if_id_p_t interface_id, + unsigned32 vers_option, + ept_lookup_handle_t *entry_handle, + unsigned32 max_ents, + unsigned32 *num_ents, + ept_entry_t entries[], + error_status_t *status) +{ + WINE_FIXME("(%p, %p, %p): stub\n", h, entry_handle, status); + + *status = EPT_S_CANT_PERFORM_OP; +} + +void ept_map(handle_t h, + uuid_p_t object, + twr_p_t map_tower, + ept_lookup_handle_t *entry_handle, + unsigned32 max_towers, + unsigned32 *num_towers, + twr_p_t *towers, + error_status_t *status) +{ + RPC_STATUS rpc_status; + RPC_SYNTAX_IDENTIFIER iface, syntax; + char *protseq; + struct registered_ept_entry *entry; + + *status = RPC_S_OK; + *num_towers = 0; + + WINE_TRACE("(%p, %p, %p, %p, %lu, %p, %p, %p)\n", h, object, map_tower, + entry_handle, max_towers, num_towers, towers, status); + + rpc_status = TowerExplode(map_tower, &iface, &syntax, &protseq, + NULL, NULL); + if (rpc_status != RPC_S_OK) + { + *status = rpc_status; + return; + } + + EnterCriticalSection(&csEpm); + + LIST_FOR_EACH_ENTRY(entry, ®istered_ept_entry_list, struct registered_ept_entry, entry) + { + if (IsEqualGUID(&entry->iface.SyntaxGUID, &iface.SyntaxGUID) && + (entry->iface.SyntaxVersion.MajorVersion == iface.SyntaxVersion.MajorVersion) && + (entry->iface.SyntaxVersion.MinorVersion >= iface.SyntaxVersion.MinorVersion) && + !memcmp(&entry->syntax, &syntax, sizeof(syntax)) && + !strcmp(entry->protseq, protseq) && + ((!object && IsEqualGUID(&entry->object, &nil_object)) || IsEqualGUID(object, &entry->object))) + { + if (*num_towers < max_towers) + { + rpc_status = TowerConstruct(&entry->iface, &entry->syntax, + entry->protseq, entry->endpoint, + entry->address, + &towers[*num_towers]); + if (rpc_status != RPC_S_OK) + { + *status = rpc_status; + break; /* FIXME: more cleanup? */ + } + } + (*num_towers)++; + } + } + + LeaveCriticalSection(&csEpm); +} + +void ept_lookup_handle_free(handle_t h, + ept_lookup_handle_t *entry_handle, + error_status_t *status) +{ + WINE_FIXME("(%p, %p, %p): stub\n", h, entry_handle, status); + + *status = EPT_S_CANT_PERFORM_OP; +} + +void ept_inq_object(handle_t h, + GUID *ept_object, + error_status_t *status) +{ + WINE_FIXME("(%p, %p, %p): stub\n", h, ept_object, status); + + *status = EPT_S_CANT_PERFORM_OP; +} + +void ept_mgmt_delete(handle_t h, + boolean32 object_speced, + uuid_p_t object, + twr_p_t tower, + error_status_t *status) +{ + WINE_FIXME("(%p, %ld, %p, %p, %p): stub\n", h, object_speced, object, tower, status); + + *status = EPT_S_CANT_PERFORM_OP; +} diff --git a/programs/rpcss/rpcss_main.c b/programs/rpcss/rpcss_main.c index 99b2d001502..bff08472a74 100644 --- a/programs/rpcss/rpcss_main.c +++ b/programs/rpcss/rpcss_main.c @@ -35,22 +35,12 @@ * these, also implement net.exe, at least for "net start" and * "net stop" (should be pretty easy I guess, assuming the rest * of the services API infrastructure works. - * - * o Is supposed to use RPC, not random kludges, to map endpoints. - * - * o Probably name services should be implemented here as well. - * - * o Wine's named pipes (in general) may not interoperate with those of - * Windows yet (?) * * o There is a looming problem regarding listening on privileged * ports. We will need to be able to coexist with SAMBA, and be able * to function without running winelib code as root. This may * take some doing, including significant reconceptualization of the * role of rpcss.exe in wine. - * - * o Who knows? Whatever rpcss does, we ought to at - * least think about doing... but what /does/ it do? */ #include @@ -62,6 +52,7 @@ #include "rpcss.h" #include "winnt.h" #include "irot.h" +#include "epm.h" #include "wine/debug.h" @@ -86,12 +77,12 @@ static BOOL RPCSS_Initialize(void) { static unsigned short irot_protseq[] = IROT_PROTSEQ; static unsigned short irot_endpoint[] = IROT_ENDPOINT; + static unsigned short epm_protseq[] = {'n','c','a','c','n','_','n','p',0}; + static unsigned short epm_endpoint[] = {'\\','p','i','p','e','\\','e','p','m','a','p','p','e','r',0}; RPC_STATUS status; WINE_TRACE("\n"); - exit_event = __wine_make_process_system(); - master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); if (!master_mutex) { WINE_ERR("Failed to create master mutex\n"); @@ -107,16 +98,38 @@ static BOOL RPCSS_Initialize(void) return FALSE; } + status = RpcServerRegisterIf(epm_v3_0_s_ifspec, NULL, NULL); + if (status != RPC_S_OK) + return status; + status = RpcServerRegisterIf(Irot_v0_2_s_ifspec, NULL, NULL); + if (status != RPC_S_OK) + { + RpcServerUnregisterIf(epm_v3_0_s_ifspec, NULL, FALSE); + return FALSE; + } + + status = RpcServerUseProtseqEpW(epm_protseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + epm_endpoint, NULL); + if (status != RPC_S_OK) + goto fail; + status = RpcServerUseProtseqEpW(irot_protseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, irot_endpoint, NULL); - if (status == RPC_S_OK) - status = RpcServerRegisterIf(Irot_v0_2_s_ifspec, NULL, NULL); - if (status == RPC_S_OK) - status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE); - else - RpcServerUnregisterIf(Irot_v0_2_s_ifspec, NULL, FALSE); + if (status != RPC_S_OK) + goto fail; - return status == RPC_S_OK; + status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE); + if (status != RPC_S_OK) + goto fail; + + exit_event = __wine_make_process_system(); + + return TRUE; + +fail: + RpcServerUnregisterIf(epm_v3_0_s_ifspec, NULL, FALSE); + RpcServerUnregisterIf(Irot_v0_2_s_ifspec, NULL, FALSE); + return FALSE; } /* returns false if we discover at the last moment that we @@ -132,6 +145,7 @@ static BOOL RPCSS_Shutdown(void) master_mutex = NULL; RpcMgmtStopServerListening(NULL); + RpcServerUnregisterIf(epm_v3_0_s_ifspec, NULL, TRUE); RpcServerUnregisterIf(Irot_v0_2_s_ifspec, NULL, TRUE); CloseHandle(exit_event);