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
27 #include "epm_towers.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
31 /* The "real" RPC portmapper endpoints that I know of are:
35 * ncacn_np: \\pipe\epmapper
39 * If the user's machine ran a DCE RPC daemon, it would
40 * probably be possible to connect to it, but there are many
41 * reasons not to, like:
42 * - the user probably does *not* run one, and probably
43 * shouldn't be forced to run one just for local COM
44 * - very few Unix systems use DCE RPC... if they run a RPC
45 * daemon at all, it's usually Sun RPC
46 * - DCE RPC registrations are persistent and saved on disk,
47 * while MS-RPC registrations are documented as non-persistent
48 * and stored only in RAM, and auto-destroyed when the process
49 * dies (something DCE RPC can't do)
51 * Of course, if the user *did* want to run a DCE RPC daemon anyway,
52 * there would be interoperability advantages, like the possibility
53 * of running a fully functional DCOM server using Wine...
56 static const struct epm_endpoints
62 { "ncacn_np", "\\pipe\\epmapper" },
63 { "ncacn_ip_tcp", "135" },
64 { "ncacn_ip_udp", "135" },
65 { "ncalrpc", "epmapper" },
66 { "ncacn_http", "593" },
69 static BOOL
start_rpcss(void)
71 static const WCHAR rpcssW
[] = {'R','p','c','S','s',0};
72 SC_HANDLE scm
, service
;
73 SERVICE_STATUS_PROCESS status
;
78 if (!(scm
= OpenSCManagerW( NULL
, NULL
, 0 )))
80 ERR( "failed to open service manager\n" );
83 if (!(service
= OpenServiceW( scm
, rpcssW
, SERVICE_START
| SERVICE_QUERY_STATUS
)))
85 ERR( "failed to open RpcSs service\n" );
86 CloseServiceHandle( scm
);
89 if (StartServiceW( service
, 0, NULL
) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING
)
91 ULONGLONG start_time
= GetTickCount64();
96 if (!QueryServiceStatusEx( service
, SC_STATUS_PROCESS_INFO
,
97 (BYTE
*)&status
, sizeof(status
), &dummy
))
99 if (status
.dwCurrentState
== SERVICE_RUNNING
)
104 if (GetTickCount64() - start_time
> 30000) break;
107 } while (status
.dwCurrentState
== SERVICE_START_PENDING
);
109 if (status
.dwCurrentState
!= SERVICE_RUNNING
)
110 WARN( "RpcSs failed to start %u\n", status
.dwCurrentState
);
112 else ERR( "failed to start RpcSs service\n" );
114 CloseServiceHandle( service
);
115 CloseServiceHandle( scm
);
119 static inline BOOL
is_epm_destination_local(RPC_BINDING_HANDLE handle
)
121 RpcBinding
*bind
= handle
;
122 const char *protseq
= bind
->Protseq
;
123 const char *network_addr
= bind
->NetworkAddr
;
125 return (!strcmp(protseq
, "ncalrpc") ||
126 (!strcmp(protseq
, "ncacn_np") &&
127 (!network_addr
|| !strcmp(network_addr
, "."))));
130 static RPC_STATUS
get_epm_handle_client(RPC_BINDING_HANDLE handle
, RPC_BINDING_HANDLE
*epm_handle
)
132 RpcBinding
*bind
= handle
;
133 const char * pszEndpoint
= NULL
;
135 RpcBinding
* epm_bind
;
139 return RPC_S_INVALID_BINDING
;
141 for (i
= 0; i
< sizeof(epm_endpoints
)/sizeof(epm_endpoints
[0]); i
++)
142 if (!strcmp(bind
->Protseq
, epm_endpoints
[i
].protseq
))
143 pszEndpoint
= epm_endpoints
[i
].endpoint
;
147 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind
->Protseq
));
148 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
151 status
= RpcBindingCopy(handle
, epm_handle
);
152 if (status
!= RPC_S_OK
) return status
;
154 epm_bind
= *epm_handle
;
155 if (epm_bind
->AuthInfo
)
157 /* don't bother with authenticating against the EPM by default
158 * (see EnableAuthEpResolution registry value) */
159 RpcAuthInfo_Release(epm_bind
->AuthInfo
);
160 epm_bind
->AuthInfo
= NULL
;
162 RPCRT4_ResolveBinding(epm_bind
, pszEndpoint
);
167 static RPC_STATUS
get_epm_handle_server(RPC_BINDING_HANDLE
*epm_handle
)
169 unsigned char string_binding
[] = "ncacn_np:.[\\\\pipe\\\\epmapper]";
171 return RpcBindingFromStringBindingA(string_binding
, epm_handle
);
174 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*__eptr
)
176 switch (__eptr
->ExceptionRecord
->ExceptionCode
)
178 case EXCEPTION_ACCESS_VIOLATION
:
179 case EXCEPTION_ILLEGAL_INSTRUCTION
:
180 return EXCEPTION_CONTINUE_SEARCH
;
182 return EXCEPTION_EXECUTE_HANDLER
;
186 static RPC_STATUS
epm_register( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
187 UUID_VECTOR
*UuidVector
, RPC_CSTR Annotation
, BOOL replace
)
189 PRPC_SERVER_INTERFACE If
= IfSpec
;
191 RPC_STATUS status
= RPC_S_OK
;
192 error_status_t status2
;
193 ept_entry_t
*entries
;
196 TRACE("(%p,%p,%p,%s) replace=%d\n", IfSpec
, BindingVector
, UuidVector
, debugstr_a((char*)Annotation
), replace
);
197 TRACE(" ifid=%s\n", debugstr_guid(&If
->InterfaceId
.SyntaxGUID
));
198 for (i
=0; i
<BindingVector
->Count
; i
++) {
199 RpcBinding
* bind
= BindingVector
->BindingH
[i
];
200 TRACE(" protseq[%d]=%s\n", i
, debugstr_a(bind
->Protseq
));
201 TRACE(" endpoint[%d]=%s\n", i
, debugstr_a(bind
->Endpoint
));
204 for (i
=0; i
<UuidVector
->Count
; i
++)
205 TRACE(" obj[%d]=%s\n", i
, debugstr_guid(UuidVector
->Uuid
[i
]));
208 if (!BindingVector
->Count
) return RPC_S_OK
;
210 entries
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*entries
) * BindingVector
->Count
* (UuidVector
? UuidVector
->Count
: 1));
212 return RPC_S_OUT_OF_MEMORY
;
214 status
= get_epm_handle_server(&handle
);
215 if (status
!= RPC_S_OK
)
217 HeapFree(GetProcessHeap(), 0, entries
);
221 for (i
= 0; i
< BindingVector
->Count
; i
++)
224 RpcBinding
* bind
= BindingVector
->BindingH
[i
];
225 for (j
= 0; j
< (UuidVector
? UuidVector
->Count
: 1); j
++)
227 status
= TowerConstruct(&If
->InterfaceId
, &If
->TransferSyntax
,
228 bind
->Protseq
, bind
->Endpoint
,
230 &entries
[i
*(UuidVector
? UuidVector
->Count
: 1) + j
].tower
);
231 if (status
!= RPC_S_OK
) break;
234 memcpy(&entries
[i
* UuidVector
->Count
].object
, &UuidVector
->Uuid
[j
], sizeof(GUID
));
236 memset(&entries
[i
].object
, 0, sizeof(entries
[i
].object
));
238 memcpy(entries
[i
].annotation
, Annotation
,
239 min(strlen((char *)Annotation
) + 1, ept_max_annotation_size
));
243 if (status
== RPC_S_OK
)
249 ept_insert(handle
, BindingVector
->Count
* (UuidVector
? UuidVector
->Count
: 1),
250 entries
, replace
, &status2
);
254 status2
= GetExceptionCode();
257 if (status2
== RPC_S_SERVER_UNAVAILABLE
&&
258 is_epm_destination_local(handle
))
263 if (status2
!= RPC_S_OK
)
264 ERR("ept_insert failed with error %d\n", status2
);
265 status
= status2
; /* FIXME: convert status? */
269 RpcBindingFree(&handle
);
271 for (i
= 0; i
< BindingVector
->Count
; i
++)
274 for (j
= 0; j
< (UuidVector
? UuidVector
->Count
: 1); j
++)
275 I_RpcFree(entries
[i
*(UuidVector
? UuidVector
->Count
: 1) + j
].tower
);
278 HeapFree(GetProcessHeap(), 0, entries
);
283 /***********************************************************************
284 * RpcEpRegisterA (RPCRT4.@)
286 RPC_STATUS WINAPI
RpcEpRegisterA( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
287 UUID_VECTOR
*UuidVector
, RPC_CSTR Annotation
)
289 return epm_register(IfSpec
, BindingVector
, UuidVector
, Annotation
, TRUE
);
292 /***********************************************************************
293 * RpcEpRegisterNoReplaceA (RPCRT4.@)
295 RPC_STATUS WINAPI
RpcEpRegisterNoReplaceA( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
296 UUID_VECTOR
*UuidVector
, RPC_CSTR Annotation
)
298 return epm_register(IfSpec
, BindingVector
, UuidVector
, Annotation
, FALSE
);
301 /***********************************************************************
302 * RpcEpRegisterW (RPCRT4.@)
304 RPC_STATUS WINAPI
RpcEpRegisterW( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
305 UUID_VECTOR
*UuidVector
, RPC_WSTR Annotation
)
307 LPSTR annA
= RPCRT4_strdupWtoA(Annotation
);
310 status
= epm_register(IfSpec
, BindingVector
, UuidVector
, (RPC_CSTR
)annA
, TRUE
);
312 HeapFree(GetProcessHeap(), 0, annA
);
316 /***********************************************************************
317 * RpcEpRegisterNoReplaceW (RPCRT4.@)
319 RPC_STATUS WINAPI
RpcEpRegisterNoReplaceW( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
320 UUID_VECTOR
*UuidVector
, RPC_WSTR Annotation
)
322 LPSTR annA
= RPCRT4_strdupWtoA(Annotation
);
325 status
= epm_register(IfSpec
, BindingVector
, UuidVector
, (RPC_CSTR
)annA
, FALSE
);
327 HeapFree(GetProcessHeap(), 0, annA
);
331 /***********************************************************************
332 * RpcEpUnregister (RPCRT4.@)
334 RPC_STATUS WINAPI
RpcEpUnregister( RPC_IF_HANDLE IfSpec
, RPC_BINDING_VECTOR
*BindingVector
,
335 UUID_VECTOR
*UuidVector
)
337 PRPC_SERVER_INTERFACE If
= IfSpec
;
339 RPC_STATUS status
= RPC_S_OK
;
340 error_status_t status2
;
341 ept_entry_t
*entries
;
344 TRACE("(%p,%p,%p)\n", IfSpec
, BindingVector
, UuidVector
);
345 TRACE(" ifid=%s\n", debugstr_guid(&If
->InterfaceId
.SyntaxGUID
));
346 for (i
=0; i
<BindingVector
->Count
; i
++) {
347 RpcBinding
* bind
= BindingVector
->BindingH
[i
];
348 TRACE(" protseq[%d]=%s\n", i
, debugstr_a(bind
->Protseq
));
349 TRACE(" endpoint[%d]=%s\n", i
, debugstr_a(bind
->Endpoint
));
352 for (i
=0; i
<UuidVector
->Count
; i
++)
353 TRACE(" obj[%d]=%s\n", i
, debugstr_guid(UuidVector
->Uuid
[i
]));
356 entries
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*entries
) * BindingVector
->Count
* (UuidVector
? UuidVector
->Count
: 1));
358 return RPC_S_OUT_OF_MEMORY
;
360 status
= get_epm_handle_server(&handle
);
361 if (status
!= RPC_S_OK
)
363 HeapFree(GetProcessHeap(), 0, entries
);
367 for (i
= 0; i
< BindingVector
->Count
; i
++)
370 RpcBinding
* bind
= BindingVector
->BindingH
[i
];
371 for (j
= 0; j
< (UuidVector
? UuidVector
->Count
: 1); j
++)
373 status
= TowerConstruct(&If
->InterfaceId
, &If
->TransferSyntax
,
374 bind
->Protseq
, bind
->Endpoint
,
376 &entries
[i
*(UuidVector
? UuidVector
->Count
: 1) + j
].tower
);
377 if (status
!= RPC_S_OK
) break;
380 memcpy(&entries
[i
* UuidVector
->Count
+ j
].object
, &UuidVector
->Uuid
[j
], sizeof(GUID
));
382 memset(&entries
[i
].object
, 0, sizeof(entries
[i
].object
));
386 if (status
== RPC_S_OK
)
390 ept_insert(handle
, BindingVector
->Count
* (UuidVector
? UuidVector
->Count
: 1),
391 entries
, TRUE
, &status2
);
395 status2
= GetExceptionCode();
398 if (status2
== RPC_S_SERVER_UNAVAILABLE
)
399 status2
= EPT_S_NOT_REGISTERED
;
400 if (status2
!= RPC_S_OK
)
401 ERR("ept_insert failed with error %d\n", status2
);
402 status
= status2
; /* FIXME: convert status? */
404 RpcBindingFree(&handle
);
406 for (i
= 0; i
< BindingVector
->Count
; i
++)
409 for (j
= 0; j
< (UuidVector
? UuidVector
->Count
: 1); j
++)
410 I_RpcFree(entries
[i
*(UuidVector
? UuidVector
->Count
: 1) + j
].tower
);
413 HeapFree(GetProcessHeap(), 0, entries
);
418 /***********************************************************************
419 * RpcEpResolveBinding (RPCRT4.@)
421 RPC_STATUS WINAPI
RpcEpResolveBinding( RPC_BINDING_HANDLE Binding
, RPC_IF_HANDLE IfSpec
)
423 PRPC_CLIENT_INTERFACE If
= IfSpec
;
424 RpcBinding
* bind
= Binding
;
426 error_status_t status2
;
428 ept_lookup_handle_t entry_handle
= NULL
;
430 twr_t
*towers
[4] = { NULL
};
431 unsigned32 num_towers
, i
;
432 GUID uuid
= GUID_NULL
;
433 char *resolved_endpoint
= NULL
;
435 TRACE("(%p,%p)\n", Binding
, IfSpec
);
436 TRACE(" protseq=%s\n", debugstr_a(bind
->Protseq
));
437 TRACE(" obj=%s\n", debugstr_guid(&bind
->ObjectUuid
));
438 TRACE(" networkaddr=%s\n", debugstr_a(bind
->NetworkAddr
));
439 TRACE(" ifid=%s\n", debugstr_guid(&If
->InterfaceId
.SyntaxGUID
));
441 /* just return for fully bound handles */
442 if (bind
->Endpoint
&& (bind
->Endpoint
[0] != '\0'))
445 status
= get_epm_handle_client(Binding
, &handle
);
446 if (status
!= RPC_S_OK
) return status
;
448 status
= TowerConstruct(&If
->InterfaceId
, &If
->TransferSyntax
, bind
->Protseq
,
449 ((RpcBinding
*)handle
)->Endpoint
,
450 bind
->NetworkAddr
, &tower
);
451 if (status
!= RPC_S_OK
)
453 WARN("couldn't get tower\n");
454 RpcBindingFree(&handle
);
462 ept_map(handle
, &uuid
, tower
, &entry_handle
, sizeof(towers
)/sizeof(towers
[0]), &num_towers
, towers
, &status2
);
463 /* FIXME: translate status2? */
467 status2
= GetExceptionCode();
470 if (status2
== RPC_S_SERVER_UNAVAILABLE
&&
471 is_epm_destination_local(handle
))
479 RpcBindingFree(&handle
);
482 if (status2
!= RPC_S_OK
)
484 ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If
->TransferSyntax
.SyntaxGUID
), bind
->Protseq
, bind
->NetworkAddr
);
488 for (i
= 0; i
< num_towers
; i
++)
490 /* only parse the tower if we haven't already found a suitable
491 * endpoint, otherwise just free the tower */
492 if (!resolved_endpoint
)
494 status
= TowerExplode(towers
[i
], NULL
, NULL
, NULL
, &resolved_endpoint
, NULL
);
495 TRACE("status = %d\n", status
);
497 I_RpcFree(towers
[i
]);
500 if (resolved_endpoint
)
502 RPCRT4_ResolveBinding(Binding
, resolved_endpoint
);
503 I_RpcFree(resolved_endpoint
);
507 WARN("couldn't find an endpoint\n");
508 return EPT_S_NOT_REGISTERED
;
511 /*****************************************************************************
512 * TowerExplode (RPCRT4.@)
514 RPC_STATUS WINAPI
TowerExplode(
515 const twr_t
*tower
, PRPC_SYNTAX_IDENTIFIER object
, PRPC_SYNTAX_IDENTIFIER syntax
,
516 char **protseq
, char **endpoint
, char **address
)
520 const unsigned char *p
;
522 const twr_uuid_floor_t
*object_floor
;
523 const twr_uuid_floor_t
*syntax_floor
;
525 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower
, object
, syntax
, protseq
,
535 tower_size
= tower
->tower_length
;
537 if (tower_size
< sizeof(u_int16
))
538 return EPT_S_NOT_REGISTERED
;
540 p
= &tower
->tower_octet_string
[0];
542 floor_count
= *(const u_int16
*)p
;
543 p
+= sizeof(u_int16
);
544 tower_size
-= sizeof(u_int16
);
545 TRACE("floor_count: %d\n", floor_count
);
546 /* FIXME: should we do something with the floor count? at the moment we don't */
548 if (tower_size
< sizeof(*object_floor
) + sizeof(*syntax_floor
))
549 return EPT_S_NOT_REGISTERED
;
551 object_floor
= (const twr_uuid_floor_t
*)p
;
552 p
+= sizeof(*object_floor
);
553 tower_size
-= sizeof(*object_floor
);
554 syntax_floor
= (const twr_uuid_floor_t
*)p
;
555 p
+= sizeof(*syntax_floor
);
556 tower_size
-= sizeof(*syntax_floor
);
558 if ((object_floor
->count_lhs
!= sizeof(object_floor
->protid
) +
559 sizeof(object_floor
->uuid
) + sizeof(object_floor
->major_version
)) ||
560 (object_floor
->protid
!= EPM_PROTOCOL_UUID
) ||
561 (object_floor
->count_rhs
!= sizeof(object_floor
->minor_version
)))
562 return EPT_S_NOT_REGISTERED
;
564 if ((syntax_floor
->count_lhs
!= sizeof(syntax_floor
->protid
) +
565 sizeof(syntax_floor
->uuid
) + sizeof(syntax_floor
->major_version
)) ||
566 (syntax_floor
->protid
!= EPM_PROTOCOL_UUID
) ||
567 (syntax_floor
->count_rhs
!= sizeof(syntax_floor
->minor_version
)))
568 return EPT_S_NOT_REGISTERED
;
570 status
= RpcTransport_ParseTopOfTower(p
, tower_size
, protseq
, address
, endpoint
);
571 if ((status
== RPC_S_OK
) && syntax
&& object
)
573 syntax
->SyntaxGUID
= syntax_floor
->uuid
;
574 syntax
->SyntaxVersion
.MajorVersion
= syntax_floor
->major_version
;
575 syntax
->SyntaxVersion
.MinorVersion
= syntax_floor
->minor_version
;
576 object
->SyntaxGUID
= object_floor
->uuid
;
577 object
->SyntaxVersion
.MajorVersion
= object_floor
->major_version
;
578 object
->SyntaxVersion
.MinorVersion
= object_floor
->minor_version
;
583 /***********************************************************************
584 * TowerConstruct (RPCRT4.@)
586 RPC_STATUS WINAPI
TowerConstruct(
587 const RPC_SYNTAX_IDENTIFIER
*object
, const RPC_SYNTAX_IDENTIFIER
*syntax
,
588 const char *protseq
, const char *endpoint
, const char *address
,
594 twr_uuid_floor_t
*object_floor
;
595 twr_uuid_floor_t
*syntax_floor
;
597 TRACE("(%p, %p, %s, %s, %s, %p)\n", object
, syntax
, debugstr_a(protseq
),
598 debugstr_a(endpoint
), debugstr_a(address
), tower
);
602 status
= RpcTransport_GetTopOfTower(NULL
, &tower_size
, protseq
, address
, endpoint
);
604 if (status
!= RPC_S_OK
)
607 tower_size
+= sizeof(u_int16
) + sizeof(*object_floor
) + sizeof(*syntax_floor
);
608 *tower
= I_RpcAllocate(FIELD_OFFSET(twr_t
, tower_octet_string
[tower_size
]));
610 return RPC_S_OUT_OF_RESOURCES
;
612 (*tower
)->tower_length
= tower_size
;
613 p
= &(*tower
)->tower_octet_string
[0];
614 *(u_int16
*)p
= 5; /* number of floors */
615 p
+= sizeof(u_int16
);
616 object_floor
= (twr_uuid_floor_t
*)p
;
617 p
+= sizeof(*object_floor
);
618 syntax_floor
= (twr_uuid_floor_t
*)p
;
619 p
+= sizeof(*syntax_floor
);
621 object_floor
->count_lhs
= sizeof(object_floor
->protid
) + sizeof(object_floor
->uuid
) +
622 sizeof(object_floor
->major_version
);
623 object_floor
->protid
= EPM_PROTOCOL_UUID
;
624 object_floor
->count_rhs
= sizeof(object_floor
->minor_version
);
625 object_floor
->uuid
= object
->SyntaxGUID
;
626 object_floor
->major_version
= object
->SyntaxVersion
.MajorVersion
;
627 object_floor
->minor_version
= object
->SyntaxVersion
.MinorVersion
;
629 syntax_floor
->count_lhs
= sizeof(syntax_floor
->protid
) + sizeof(syntax_floor
->uuid
) +
630 sizeof(syntax_floor
->major_version
);
631 syntax_floor
->protid
= EPM_PROTOCOL_UUID
;
632 syntax_floor
->count_rhs
= sizeof(syntax_floor
->minor_version
);
633 syntax_floor
->uuid
= syntax
->SyntaxGUID
;
634 syntax_floor
->major_version
= syntax
->SyntaxVersion
.MajorVersion
;
635 syntax_floor
->minor_version
= syntax
->SyntaxVersion
.MinorVersion
;
637 status
= RpcTransport_GetTopOfTower(p
, &tower_size
, protseq
, address
, endpoint
);
638 if (status
!= RPC_S_OK
)
647 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
649 return HeapAlloc(GetProcessHeap(), 0, len
);
652 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
654 HeapFree(GetProcessHeap(), 0, ptr
);