1 /*
2 * RPC endpoint mapper
3 *
4 * Copyright 2002 Greg Turner
5 * Copyright 2001 Ove Kåven, TransGaming Technologies
6 * Copyright 2008 Robert Shearman (for CodeWeavers)
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28
29 #include "rpc.h"
30
31 #include "wine/debug.h"
32 #include "wine/exception.h"
33
34 #include "rpc_binding.h"
35 #include "epm.h"
36 #include "epm_towers.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39
40 /* The "real" RPC portmapper endpoints that I know of are:
41 *
42 * ncadg_ip_udp: 135
43 * ncacn_ip_tcp: 135
44 * ncacn_np: \\pipe\epmapper
45 * ncalrpc: epmapper
46 * ncacn_http: 593
47 *
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)
59 *
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...
63 */
64
65 static const struct epm_endpoints
66 {
67 const char *protseq;
68 const char *endpoint;
69 } epm_endpoints[] =
70 {
71 { "ncacn_np", "\\pipe\\epmapper" },
72 { "ncacn_ip_tcp", "135" },
73 { "ncacn_ip_udp", "135" },
74 { "ncalrpc", "epmapper" },
75 { "ncacn_http", "593" },
76 };
77
78 static BOOL start_rpcss(void)
79 {
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;
85
86 TRACE("\n");
87
88 ZeroMemory(&si, sizeof(STARTUPINFOA));
89 si.cb = sizeof(STARTUPINFOA);
90 GetSystemDirectoryW( cmd, MAX_PATH - sizeof(rpcss)/sizeof(WCHAR) );
91 lstrcatW( cmd, rpcss );
92
93 rslt = CreateProcessW( cmd, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
94
95 if (rslt)
96 {
97 CloseHandle(pi.hProcess);
98 CloseHandle(pi.hThread);
99 Sleep(100);
100 }
101
102 return rslt;
103 }
104
105 static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle)
106 {
107 RpcBinding *bind = handle;
108 const char *protseq = bind->Protseq;
109 const char *network_addr = bind->NetworkAddr;
110
111 return (!strcmp(protseq, "ncalrpc") ||
112 (!strcmp(protseq, "ncacn_np") &&
113 (!network_addr || !strcmp(network_addr, "."))));
114 }
115
116 static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle)
117 {
118 RpcBinding *bind = handle;
119 const char * pszEndpoint = NULL;
120 RPC_STATUS status;
121 RpcBinding* epm_bind;
122 unsigned int i;
123
124 if (bind->server)
125 return RPC_S_INVALID_BINDING;
126
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;
130
131 if (!pszEndpoint)
132 {
133 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq));
134 return RPC_S_PROTSEQ_NOT_SUPPORTED;
135 }
136
137 status = RpcBindingCopy(handle, epm_handle);
138 if (status != RPC_S_OK) return status;
139
140 epm_bind = *epm_handle;
141 if (epm_bind->AuthInfo)
142 {
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;
147 }
148 RPCRT4_ResolveBinding(epm_bind, pszEndpoint);
149 TRACE("RPC_S_OK\n");
150 return RPC_S_OK;
151 }
152
153 static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle)
154 {
155 unsigned char string_binding[] = "ncacn_np:.[\\\\pipe\\\\epmapper]";
156
157 return RpcBindingFromStringBindingA(string_binding, epm_handle);
158 }
159
160 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr)
161 {
162 switch (GetExceptionCode())
163 {
164 case EXCEPTION_ACCESS_VIOLATION:
165 case EXCEPTION_ILLEGAL_INSTRUCTION:
166 return EXCEPTION_CONTINUE_SEARCH;
167 default:
168 return EXCEPTION_EXECUTE_HANDLER;
169 }
170 }
171
172 /***********************************************************************
173 * RpcEpRegisterA (RPCRT4.@)
174 */
175 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
176 UUID_VECTOR *UuidVector, RPC_CSTR Annotation )
177 {
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;
184
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));
191 }
192 if (UuidVector) {
193 for (i=0; i<UuidVector->Count; i++)
194 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
195 }
196
197 if (!BindingVector->Count) return RPC_S_OK;
198
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;
202
203 status = get_epm_handle_server(&handle);
204 if (status != RPC_S_OK)
205 {
206 HeapFree(GetProcessHeap(), 0, entries);
207 return status;
208 }
209
210 for (i = 0; i < BindingVector->Count; i++)
211 {
212 unsigned j;
213 RpcBinding* bind = BindingVector->BindingH[i];
214 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
215 {
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;
221
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));
229 }
230 }
231
232 if (status == RPC_S_OK)
233 {
234 while (TRUE)
235 {
236 __TRY
237 {
238 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
239 entries, TRUE, &status2);
240 }
241 __EXCEPT(rpc_filter)
242 {
243 status2 = GetExceptionCode();
244 }
245 __ENDTRY
246 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
247 is_epm_destination_local(handle))
248 {
249 if (start_rpcss())
250 continue;
251 }
252 if (status2 != RPC_S_OK)
253 ERR("ept_insert failed with error %d\n", status2);
254 status = status2; /* FIXME: convert status? */
255 break;
256 }
257 }
258 RpcBindingFree(&handle);
259
260 for (i = 0; i < BindingVector->Count; i++)
261 {
262 unsigned j;
263 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
264 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
265 }
266
267 HeapFree(GetProcessHeap(), 0, entries);
268
269 return status;
270 }
271
272 /***********************************************************************
273 * RpcEpRegisterW (RPCRT4.@)
274 */
275 RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
276 UUID_VECTOR *UuidVector, RPC_WSTR Annotation )
277 {
278 LPSTR annA = RPCRT4_strdupWtoA(Annotation);
279 RPC_STATUS status;
280
281 status = RpcEpRegisterA(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA);
282
283 HeapFree(GetProcessHeap(), 0, annA);
284 return status;
285 }
286
287 /***********************************************************************
288 * RpcEpUnregister (RPCRT4.@)
289 */
290 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
291 UUID_VECTOR *UuidVector )
292 {
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;
299
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));
306 }
307 if (UuidVector) {
308 for (i=0; i<UuidVector->Count; i++)
309 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
310 }
311
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;
315
316 status = get_epm_handle_server(&handle);
317 if (status != RPC_S_OK)
318 {
319 HeapFree(GetProcessHeap(), 0, entries);
320 return status;
321 }
322
323 for (i = 0; i < BindingVector->Count; i++)
324 {
325 unsigned j;
326 RpcBinding* bind = BindingVector->BindingH[i];
327 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
328 {
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;
334
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));
339 }
340 }
341
342 if (status == RPC_S_OK)
343 {
344 __TRY
345 {
346 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
347 entries, TRUE, &status2);
348 }
349 __EXCEPT(rpc_filter)
350 {
351 status2 = GetExceptionCode();
352 }
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? */
359 }
360 RpcBindingFree(&handle);
361
362 for (i = 0; i < BindingVector->Count; i++)
363 {
364 unsigned j;
365 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
366 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
367 }
368
369 HeapFree(GetProcessHeap(), 0, entries);
370
371 return status;
372 }
373
374 /***********************************************************************
375 * RpcEpResolveBinding (RPCRT4.@)
376 */
377 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec )
378 {
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;
390
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));
396
397 /* just return for fully bound handles */
398 if (bind->Endpoint && (bind->Endpoint[0] != '\0'))
399 return RPC_S_OK;
400
401 status = get_epm_handle_client(Binding, &handle);
402 if (status != RPC_S_OK) return status;
403
404 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq,
405 ((RpcBinding *)handle)->Endpoint,
406 bind->NetworkAddr, &tower);
407 if (status != RPC_S_OK)
408 {
409 WARN("couldn't get tower\n");
410 RpcBindingFree(&handle);
411 return status;
412 }
413
414 while (TRUE)
415 {
416 __TRY
417 {
418 ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2);
419 /* FIXME: translate status2? */
420 }
421 __EXCEPT(rpc_filter)
422 {
423 status2 = GetExceptionCode();
424 }
425 __ENDTRY
426 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
427 is_epm_destination_local(handle))
428 {
429 if (start_rpcss())
430 continue;
431 }
432 break;
433 };
434
435 RpcBindingFree(&handle);
436 I_RpcFree(tower);
437
438 if (status2 != RPC_S_OK)
439 {
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;
442 }
443
444 for (i = 0; i < num_towers; i++)
445 {
446 /* only parse the tower if we haven't already found a suitable
447 * endpoint, otherwise just free the tower */
448 if (!resolved_endpoint)
449 {
450 status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL);
451 TRACE("status = %d\n", status);
452 }
453 I_RpcFree(towers[i]);
454 }
455
456 if (resolved_endpoint)
457 {
458 RPCRT4_ResolveBinding(Binding, resolved_endpoint);
459 I_RpcFree(resolved_endpoint);
460 return RPC_S_OK;
461 }
462
463 WARN("couldn't find an endpoint\n");
464 return EPT_S_NOT_REGISTERED;
465 }
466
467 /*****************************************************************************
468 * TowerExplode (RPCRT4.@)
469 */
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)
473 {
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;
480
481 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower, object, syntax, protseq,
482 endpoint, address);
483
484 if (protseq)
485 *protseq = NULL;
486 if (endpoint)
487 *endpoint = NULL;
488 if (address)
489 *address = NULL;
490
491 tower_size = tower->tower_length;
492
493 if (tower_size < sizeof(u_int16))
494 return EPT_S_NOT_REGISTERED;
495
496 p = &tower->tower_octet_string[0];
497
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 */
503
504 if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor))
505 return EPT_S_NOT_REGISTERED;
506
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);
513
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;
519
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;
525
526 status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint);
527 if ((status == RPC_S_OK) && syntax && object)
528 {
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;
535 }
536 return status;
537 }
538
539 /***********************************************************************
540 * TowerConstruct (RPCRT4.@)
541 */
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)
546 {
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;
552
553 TRACE("(%p, %p, %s, %s, %s, %p)\n", object, syntax, debugstr_a(protseq),
554 debugstr_a(endpoint), debugstr_a(address), tower);
555
556 *tower = NULL;
557
558 status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint);
559
560 if (status != RPC_S_OK)
561 return status;
562
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;
567
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);
576
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;
584
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;
592
593 status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint);
594 if (status != RPC_S_OK)
595 {
596 I_RpcFree(*tower);
597 *tower = NULL;
598 return status;
599 }
600 return RPC_S_OK;
601 }
602
603 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
604 {
605 return HeapAlloc(GetProcessHeap(), 0, len);
606 }
607
608 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
609 {
610 HeapFree(GetProcessHeap(), 0, ptr);
611 }
612
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.