msi: Correct the setting of environment variables.
[wine.git] / dlls / rpcrt4 / rpc_epmap.c
blobb81367e41602dd18a216c91d8423c0dff37411bb
1 /*
2 * RPC endpoint mapper
4 * Copyright 2002 Greg Turner
5 * Copyright 2001 Ove Kåven, TransGaming Technologies
6 * Copyright 2008 Robert Shearman (for CodeWeavers)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
29 #include "rpc.h"
31 #include "wine/debug.h"
32 #include "wine/exception.h"
34 #include "rpc_binding.h"
35 #include "epm.h"
36 #include "epm_towers.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 /* The "real" RPC portmapper endpoints that I know of are:
42 * ncadg_ip_udp: 135
43 * ncacn_ip_tcp: 135
44 * ncacn_np: \\pipe\epmapper
45 * ncalrpc: epmapper
46 * ncacn_http: 593
48 * If the user's machine ran a DCE RPC daemon, it would
49 * probably be possible to connect to it, but there are many
50 * reasons not to, like:
51 * - the user probably does *not* run one, and probably
52 * shouldn't be forced to run one just for local COM
53 * - very few Unix systems use DCE RPC... if they run a RPC
54 * daemon at all, it's usually Sun RPC
55 * - DCE RPC registrations are persistent and saved on disk,
56 * while MS-RPC registrations are documented as non-persistent
57 * and stored only in RAM, and auto-destroyed when the process
58 * dies (something DCE RPC can't do)
60 * Of course, if the user *did* want to run a DCE RPC daemon anyway,
61 * there would be interoperability advantages, like the possibility
62 * of running a fully functional DCOM server using Wine...
65 static const struct epm_endpoints
67 const char *protseq;
68 const char *endpoint;
69 } epm_endpoints[] =
71 { "ncacn_np", "\\pipe\\epmapper" },
72 { "ncacn_ip_tcp", "135" },
73 { "ncacn_ip_udp", "135" },
74 { "ncalrpc", "epmapper" },
75 { "ncacn_http", "593" },
78 static BOOL start_rpcss(void)
80 PROCESS_INFORMATION pi;
81 STARTUPINFOW si;
82 WCHAR cmd[MAX_PATH];
83 static const WCHAR rpcss[] = {'\\','r','p','c','s','s','.','e','x','e',0};
84 BOOL rslt;
86 TRACE("\n");
88 ZeroMemory(&si, sizeof(STARTUPINFOA));
89 si.cb = sizeof(STARTUPINFOA);
90 GetSystemDirectoryW( cmd, MAX_PATH - sizeof(rpcss)/sizeof(WCHAR) );
91 lstrcatW( cmd, rpcss );
93 rslt = CreateProcessW( cmd, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
95 if (rslt)
97 CloseHandle(pi.hProcess);
98 CloseHandle(pi.hThread);
99 Sleep(100);
102 return rslt;
105 static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle)
107 RpcBinding *bind = handle;
108 const char *protseq = bind->Protseq;
109 const char *network_addr = bind->NetworkAddr;
111 return (!strcmp(protseq, "ncalrpc") ||
112 (!strcmp(protseq, "ncacn_np") &&
113 (!network_addr || !strcmp(network_addr, "."))));
116 static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle)
118 RpcBinding *bind = handle;
119 const char * pszEndpoint = NULL;
120 RPC_STATUS status;
121 RpcBinding* epm_bind;
122 unsigned int i;
124 if (bind->server)
125 return RPC_S_INVALID_BINDING;
127 for (i = 0; i < sizeof(epm_endpoints)/sizeof(epm_endpoints[0]); i++)
128 if (!strcmp(bind->Protseq, epm_endpoints[i].protseq))
129 pszEndpoint = epm_endpoints[i].endpoint;
131 if (!pszEndpoint)
133 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq));
134 return RPC_S_PROTSEQ_NOT_SUPPORTED;
137 status = RpcBindingCopy(handle, epm_handle);
138 if (status != RPC_S_OK) return status;
140 epm_bind = *epm_handle;
141 if (epm_bind->AuthInfo)
143 /* don't bother with authenticating against the EPM by default
144 * (see EnableAuthEpResolution registry value) */
145 RpcAuthInfo_Release(epm_bind->AuthInfo);
146 epm_bind->AuthInfo = NULL;
148 RPCRT4_ResolveBinding(epm_bind, pszEndpoint);
149 TRACE("RPC_S_OK\n");
150 return RPC_S_OK;
153 static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle)
155 unsigned char string_binding[] = "ncacn_np:.[\\\\pipe\\\\epmapper]";
157 return RpcBindingFromStringBindingA(string_binding, epm_handle);
160 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr)
162 switch (GetExceptionCode())
164 case EXCEPTION_ACCESS_VIOLATION:
165 case EXCEPTION_ILLEGAL_INSTRUCTION:
166 return EXCEPTION_CONTINUE_SEARCH;
167 default:
168 return EXCEPTION_EXECUTE_HANDLER;
172 /***********************************************************************
173 * RpcEpRegisterA (RPCRT4.@)
175 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
176 UUID_VECTOR *UuidVector, RPC_CSTR Annotation )
178 PRPC_SERVER_INTERFACE If = IfSpec;
179 ULONG i;
180 RPC_STATUS status = RPC_S_OK;
181 error_status_t status2;
182 ept_entry_t *entries;
183 handle_t handle;
185 TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a((char*)Annotation));
186 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
187 for (i=0; i<BindingVector->Count; i++) {
188 RpcBinding* bind = BindingVector->BindingH[i];
189 TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq));
190 TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint));
192 if (UuidVector) {
193 for (i=0; i<UuidVector->Count; i++)
194 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
197 if (!BindingVector->Count) return RPC_S_OK;
199 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
200 if (!entries)
201 return RPC_S_OUT_OF_MEMORY;
203 status = get_epm_handle_server(&handle);
204 if (status != RPC_S_OK)
206 HeapFree(GetProcessHeap(), 0, entries);
207 return status;
210 for (i = 0; i < BindingVector->Count; i++)
212 unsigned j;
213 RpcBinding* bind = BindingVector->BindingH[i];
214 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
216 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
217 bind->Protseq, bind->Endpoint,
218 bind->NetworkAddr,
219 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
220 if (status != RPC_S_OK) break;
222 if (UuidVector)
223 memcpy(&entries[i * UuidVector->Count].object, &UuidVector->Uuid[j], sizeof(GUID));
224 else
225 memset(&entries[i].object, 0, sizeof(entries[i].object));
226 if (Annotation)
227 memcpy(entries[i].annotation, Annotation,
228 min(strlen((char *)Annotation) + 1, ept_max_annotation_size));
232 if (status == RPC_S_OK)
234 while (TRUE)
236 __TRY
238 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
239 entries, TRUE, &status2);
241 __EXCEPT(rpc_filter)
243 status2 = GetExceptionCode();
245 __ENDTRY
246 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
247 is_epm_destination_local(handle))
249 if (start_rpcss())
250 continue;
252 if (status2 != RPC_S_OK)
253 ERR("ept_insert failed with error %d\n", status2);
254 status = status2; /* FIXME: convert status? */
255 break;
258 RpcBindingFree(&handle);
260 for (i = 0; i < BindingVector->Count; i++)
262 unsigned j;
263 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
264 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
267 HeapFree(GetProcessHeap(), 0, entries);
269 return status;
272 /***********************************************************************
273 * RpcEpRegisterW (RPCRT4.@)
275 RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
276 UUID_VECTOR *UuidVector, RPC_WSTR Annotation )
278 LPSTR annA = RPCRT4_strdupWtoA(Annotation);
279 RPC_STATUS status;
281 status = RpcEpRegisterA(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA);
283 HeapFree(GetProcessHeap(), 0, annA);
284 return status;
287 /***********************************************************************
288 * RpcEpUnregister (RPCRT4.@)
290 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
291 UUID_VECTOR *UuidVector )
293 PRPC_SERVER_INTERFACE If = IfSpec;
294 ULONG i;
295 RPC_STATUS status = RPC_S_OK;
296 error_status_t status2;
297 ept_entry_t *entries;
298 handle_t handle;
300 TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector);
301 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
302 for (i=0; i<BindingVector->Count; i++) {
303 RpcBinding* bind = BindingVector->BindingH[i];
304 TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq));
305 TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint));
307 if (UuidVector) {
308 for (i=0; i<UuidVector->Count; i++)
309 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
312 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
313 if (!entries)
314 return RPC_S_OUT_OF_MEMORY;
316 status = get_epm_handle_server(&handle);
317 if (status != RPC_S_OK)
319 HeapFree(GetProcessHeap(), 0, entries);
320 return status;
323 for (i = 0; i < BindingVector->Count; i++)
325 unsigned j;
326 RpcBinding* bind = BindingVector->BindingH[i];
327 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
329 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
330 bind->Protseq, bind->Endpoint,
331 bind->NetworkAddr,
332 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
333 if (status != RPC_S_OK) break;
335 if (UuidVector)
336 memcpy(&entries[i * UuidVector->Count + j].object, &UuidVector->Uuid[j], sizeof(GUID));
337 else
338 memset(&entries[i].object, 0, sizeof(entries[i].object));
342 if (status == RPC_S_OK)
344 __TRY
346 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
347 entries, TRUE, &status2);
349 __EXCEPT(rpc_filter)
351 status2 = GetExceptionCode();
353 __ENDTRY
354 if (status2 == RPC_S_SERVER_UNAVAILABLE)
355 status2 = EPT_S_NOT_REGISTERED;
356 if (status2 != RPC_S_OK)
357 ERR("ept_insert failed with error %d\n", status2);
358 status = status2; /* FIXME: convert status? */
360 RpcBindingFree(&handle);
362 for (i = 0; i < BindingVector->Count; i++)
364 unsigned j;
365 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
366 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
369 HeapFree(GetProcessHeap(), 0, entries);
371 return status;
374 /***********************************************************************
375 * RpcEpResolveBinding (RPCRT4.@)
377 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec )
379 PRPC_CLIENT_INTERFACE If = IfSpec;
380 RpcBinding* bind = Binding;
381 RPC_STATUS status;
382 error_status_t status2;
383 handle_t handle;
384 ept_lookup_handle_t entry_handle = NULL;
385 twr_t *tower;
386 twr_t *towers[4] = { NULL };
387 unsigned32 num_towers, i;
388 GUID uuid = GUID_NULL;
389 char *resolved_endpoint = NULL;
391 TRACE("(%p,%p)\n", Binding, IfSpec);
392 TRACE(" protseq=%s\n", debugstr_a(bind->Protseq));
393 TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid));
394 TRACE(" networkaddr=%s\n", debugstr_a(bind->NetworkAddr));
395 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
397 /* just return for fully bound handles */
398 if (bind->Endpoint && (bind->Endpoint[0] != '\0'))
399 return RPC_S_OK;
401 status = get_epm_handle_client(Binding, &handle);
402 if (status != RPC_S_OK) return status;
404 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq,
405 ((RpcBinding *)handle)->Endpoint,
406 bind->NetworkAddr, &tower);
407 if (status != RPC_S_OK)
409 WARN("couldn't get tower\n");
410 RpcBindingFree(&handle);
411 return status;
414 while (TRUE)
416 __TRY
418 ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2);
419 /* FIXME: translate status2? */
421 __EXCEPT(rpc_filter)
423 status2 = GetExceptionCode();
425 __ENDTRY
426 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
427 is_epm_destination_local(handle))
429 if (start_rpcss())
430 continue;
432 break;
435 RpcBindingFree(&handle);
436 I_RpcFree(tower);
438 if (status2 != RPC_S_OK)
440 ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), bind->Protseq, bind->NetworkAddr);
441 return status2;
444 for (i = 0; i < num_towers; i++)
446 /* only parse the tower if we haven't already found a suitable
447 * endpoint, otherwise just free the tower */
448 if (!resolved_endpoint)
450 status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL);
451 TRACE("status = %d\n", status);
453 I_RpcFree(towers[i]);
456 if (resolved_endpoint)
458 RPCRT4_ResolveBinding(Binding, resolved_endpoint);
459 I_RpcFree(resolved_endpoint);
460 return RPC_S_OK;
463 WARN("couldn't find an endpoint\n");
464 return EPT_S_NOT_REGISTERED;
467 /*****************************************************************************
468 * TowerExplode (RPCRT4.@)
470 RPC_STATUS WINAPI TowerExplode(
471 const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax,
472 char **protseq, char **endpoint, char **address)
474 size_t tower_size;
475 RPC_STATUS status;
476 const unsigned char *p;
477 u_int16 floor_count;
478 const twr_uuid_floor_t *object_floor;
479 const twr_uuid_floor_t *syntax_floor;
481 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower, object, syntax, protseq,
482 endpoint, address);
484 if (protseq)
485 *protseq = NULL;
486 if (endpoint)
487 *endpoint = NULL;
488 if (address)
489 *address = NULL;
491 tower_size = tower->tower_length;
493 if (tower_size < sizeof(u_int16))
494 return EPT_S_NOT_REGISTERED;
496 p = &tower->tower_octet_string[0];
498 floor_count = *(const u_int16 *)p;
499 p += sizeof(u_int16);
500 tower_size -= sizeof(u_int16);
501 TRACE("floor_count: %d\n", floor_count);
502 /* FIXME: should we do something with the floor count? at the moment we don't */
504 if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor))
505 return EPT_S_NOT_REGISTERED;
507 object_floor = (const twr_uuid_floor_t *)p;
508 p += sizeof(*object_floor);
509 tower_size -= sizeof(*object_floor);
510 syntax_floor = (const twr_uuid_floor_t *)p;
511 p += sizeof(*syntax_floor);
512 tower_size -= sizeof(*syntax_floor);
514 if ((object_floor->count_lhs != sizeof(object_floor->protid) +
515 sizeof(object_floor->uuid) + sizeof(object_floor->major_version)) ||
516 (object_floor->protid != EPM_PROTOCOL_UUID) ||
517 (object_floor->count_rhs != sizeof(object_floor->minor_version)))
518 return EPT_S_NOT_REGISTERED;
520 if ((syntax_floor->count_lhs != sizeof(syntax_floor->protid) +
521 sizeof(syntax_floor->uuid) + sizeof(syntax_floor->major_version)) ||
522 (syntax_floor->protid != EPM_PROTOCOL_UUID) ||
523 (syntax_floor->count_rhs != sizeof(syntax_floor->minor_version)))
524 return EPT_S_NOT_REGISTERED;
526 status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint);
527 if ((status == RPC_S_OK) && syntax && object)
529 syntax->SyntaxGUID = syntax_floor->uuid;
530 syntax->SyntaxVersion.MajorVersion = syntax_floor->major_version;
531 syntax->SyntaxVersion.MinorVersion = syntax_floor->minor_version;
532 object->SyntaxGUID = object_floor->uuid;
533 object->SyntaxVersion.MajorVersion = object_floor->major_version;
534 object->SyntaxVersion.MinorVersion = object_floor->minor_version;
536 return status;
539 /***********************************************************************
540 * TowerConstruct (RPCRT4.@)
542 RPC_STATUS WINAPI TowerConstruct(
543 const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax,
544 const char *protseq, const char *endpoint, const char *address,
545 twr_t **tower)
547 size_t tower_size;
548 RPC_STATUS status;
549 unsigned char *p;
550 twr_uuid_floor_t *object_floor;
551 twr_uuid_floor_t *syntax_floor;
553 TRACE("(%p, %p, %s, %s, %s, %p)\n", object, syntax, debugstr_a(protseq),
554 debugstr_a(endpoint), debugstr_a(address), tower);
556 *tower = NULL;
558 status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint);
560 if (status != RPC_S_OK)
561 return status;
563 tower_size += sizeof(u_int16) + sizeof(*object_floor) + sizeof(*syntax_floor);
564 *tower = I_RpcAllocate(FIELD_OFFSET(twr_t, tower_octet_string[tower_size]));
565 if (!*tower)
566 return RPC_S_OUT_OF_RESOURCES;
568 (*tower)->tower_length = tower_size;
569 p = &(*tower)->tower_octet_string[0];
570 *(u_int16 *)p = 5; /* number of floors */
571 p += sizeof(u_int16);
572 object_floor = (twr_uuid_floor_t *)p;
573 p += sizeof(*object_floor);
574 syntax_floor = (twr_uuid_floor_t *)p;
575 p += sizeof(*syntax_floor);
577 object_floor->count_lhs = sizeof(object_floor->protid) + sizeof(object_floor->uuid) +
578 sizeof(object_floor->major_version);
579 object_floor->protid = EPM_PROTOCOL_UUID;
580 object_floor->count_rhs = sizeof(object_floor->minor_version);
581 object_floor->uuid = object->SyntaxGUID;
582 object_floor->major_version = object->SyntaxVersion.MajorVersion;
583 object_floor->minor_version = object->SyntaxVersion.MinorVersion;
585 syntax_floor->count_lhs = sizeof(syntax_floor->protid) + sizeof(syntax_floor->uuid) +
586 sizeof(syntax_floor->major_version);
587 syntax_floor->protid = EPM_PROTOCOL_UUID;
588 syntax_floor->count_rhs = sizeof(syntax_floor->minor_version);
589 syntax_floor->uuid = syntax->SyntaxGUID;
590 syntax_floor->major_version = syntax->SyntaxVersion.MajorVersion;
591 syntax_floor->minor_version = syntax->SyntaxVersion.MinorVersion;
593 status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint);
594 if (status != RPC_S_OK)
596 I_RpcFree(*tower);
597 *tower = NULL;
598 return status;
600 return RPC_S_OK;
603 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
605 return HeapAlloc(GetProcessHeap(), 0, len);
608 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
610 HeapFree(GetProcessHeap(), 0, ptr);