wevtapi: Add EvtOpenLog stub.
[wine.git] / dlls / rpcrt4 / rpc_epmap.c
blob1380bf34286733a52574d167dfac6af761c51a7d
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"
28 #include "winsvc.h"
30 #include "rpc.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
35 #include "rpc_binding.h"
36 #include "epm.h"
37 #include "epm_towers.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41 /* The "real" RPC portmapper endpoints that I know of are:
43 * ncadg_ip_udp: 135
44 * ncacn_ip_tcp: 135
45 * ncacn_np: \\pipe\epmapper
46 * ncalrpc: epmapper
47 * ncacn_http: 593
49 * If the user's machine ran a DCE RPC daemon, it would
50 * probably be possible to connect to it, but there are many
51 * reasons not to, like:
52 * - the user probably does *not* run one, and probably
53 * shouldn't be forced to run one just for local COM
54 * - very few Unix systems use DCE RPC... if they run a RPC
55 * daemon at all, it's usually Sun RPC
56 * - DCE RPC registrations are persistent and saved on disk,
57 * while MS-RPC registrations are documented as non-persistent
58 * and stored only in RAM, and auto-destroyed when the process
59 * dies (something DCE RPC can't do)
61 * Of course, if the user *did* want to run a DCE RPC daemon anyway,
62 * there would be interoperability advantages, like the possibility
63 * of running a fully functional DCOM server using Wine...
66 static const struct epm_endpoints
68 const char *protseq;
69 const char *endpoint;
70 } epm_endpoints[] =
72 { "ncacn_np", "\\pipe\\epmapper" },
73 { "ncacn_ip_tcp", "135" },
74 { "ncacn_ip_udp", "135" },
75 { "ncalrpc", "epmapper" },
76 { "ncacn_http", "593" },
79 static BOOL start_rpcss(void)
81 static const WCHAR rpcssW[] = {'R','p','c','S','s',0};
82 SC_HANDLE scm, service;
83 SERVICE_STATUS_PROCESS status;
84 BOOL ret = FALSE;
86 TRACE("\n");
88 if (!(scm = OpenSCManagerW( NULL, NULL, 0 )))
90 ERR( "failed to open service manager\n" );
91 return FALSE;
93 if (!(service = OpenServiceW( scm, rpcssW, SERVICE_START | SERVICE_QUERY_STATUS )))
95 ERR( "failed to open RpcSs service\n" );
96 CloseServiceHandle( scm );
97 return FALSE;
99 if (StartServiceW( service, 0, NULL ) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
101 ULONGLONG start_time = GetTickCount64();
104 DWORD dummy;
106 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO,
107 (BYTE *)&status, sizeof(status), &dummy ))
108 break;
109 if (status.dwCurrentState == SERVICE_RUNNING)
111 ret = TRUE;
112 break;
114 if (GetTickCount64() - start_time > 30000) break;
115 Sleep( 100 );
117 } while (status.dwCurrentState == SERVICE_START_PENDING);
119 if (status.dwCurrentState != SERVICE_RUNNING)
120 WARN( "RpcSs failed to start %u\n", status.dwCurrentState );
122 else ERR( "failed to start RpcSs service\n" );
124 CloseServiceHandle( service );
125 CloseServiceHandle( scm );
126 return ret;
129 static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle)
131 RpcBinding *bind = handle;
132 const char *protseq = bind->Protseq;
133 const char *network_addr = bind->NetworkAddr;
135 return (!strcmp(protseq, "ncalrpc") ||
136 (!strcmp(protseq, "ncacn_np") &&
137 (!network_addr || !strcmp(network_addr, "."))));
140 static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle)
142 RpcBinding *bind = handle;
143 const char * pszEndpoint = NULL;
144 RPC_STATUS status;
145 RpcBinding* epm_bind;
146 unsigned int i;
148 if (bind->server)
149 return RPC_S_INVALID_BINDING;
151 for (i = 0; i < sizeof(epm_endpoints)/sizeof(epm_endpoints[0]); i++)
152 if (!strcmp(bind->Protseq, epm_endpoints[i].protseq))
153 pszEndpoint = epm_endpoints[i].endpoint;
155 if (!pszEndpoint)
157 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq));
158 return RPC_S_PROTSEQ_NOT_SUPPORTED;
161 status = RpcBindingCopy(handle, epm_handle);
162 if (status != RPC_S_OK) return status;
164 epm_bind = *epm_handle;
165 if (epm_bind->AuthInfo)
167 /* don't bother with authenticating against the EPM by default
168 * (see EnableAuthEpResolution registry value) */
169 RpcAuthInfo_Release(epm_bind->AuthInfo);
170 epm_bind->AuthInfo = NULL;
172 RPCRT4_ResolveBinding(epm_bind, pszEndpoint);
173 TRACE("RPC_S_OK\n");
174 return RPC_S_OK;
177 static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle)
179 unsigned char string_binding[] = "ncacn_np:.[\\\\pipe\\\\epmapper]";
181 return RpcBindingFromStringBindingA(string_binding, epm_handle);
184 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr)
186 switch (GetExceptionCode())
188 case EXCEPTION_ACCESS_VIOLATION:
189 case EXCEPTION_ILLEGAL_INSTRUCTION:
190 return EXCEPTION_CONTINUE_SEARCH;
191 default:
192 return EXCEPTION_EXECUTE_HANDLER;
196 static RPC_STATUS epm_register( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
197 UUID_VECTOR *UuidVector, RPC_CSTR Annotation, BOOL replace )
199 PRPC_SERVER_INTERFACE If = IfSpec;
200 ULONG i;
201 RPC_STATUS status = RPC_S_OK;
202 error_status_t status2;
203 ept_entry_t *entries;
204 handle_t handle;
206 TRACE("(%p,%p,%p,%s) replace=%d\n", IfSpec, BindingVector, UuidVector, debugstr_a((char*)Annotation), replace);
207 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
208 for (i=0; i<BindingVector->Count; i++) {
209 RpcBinding* bind = BindingVector->BindingH[i];
210 TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq));
211 TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint));
213 if (UuidVector) {
214 for (i=0; i<UuidVector->Count; i++)
215 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
218 if (!BindingVector->Count) return RPC_S_OK;
220 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
221 if (!entries)
222 return RPC_S_OUT_OF_MEMORY;
224 status = get_epm_handle_server(&handle);
225 if (status != RPC_S_OK)
227 HeapFree(GetProcessHeap(), 0, entries);
228 return status;
231 for (i = 0; i < BindingVector->Count; i++)
233 unsigned j;
234 RpcBinding* bind = BindingVector->BindingH[i];
235 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
237 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
238 bind->Protseq, bind->Endpoint,
239 bind->NetworkAddr,
240 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
241 if (status != RPC_S_OK) break;
243 if (UuidVector)
244 memcpy(&entries[i * UuidVector->Count].object, &UuidVector->Uuid[j], sizeof(GUID));
245 else
246 memset(&entries[i].object, 0, sizeof(entries[i].object));
247 if (Annotation)
248 memcpy(entries[i].annotation, Annotation,
249 min(strlen((char *)Annotation) + 1, ept_max_annotation_size));
253 if (status == RPC_S_OK)
255 while (TRUE)
257 __TRY
259 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
260 entries, replace, &status2);
262 __EXCEPT(rpc_filter)
264 status2 = GetExceptionCode();
266 __ENDTRY
267 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
268 is_epm_destination_local(handle))
270 if (start_rpcss())
271 continue;
273 if (status2 != RPC_S_OK)
274 ERR("ept_insert failed with error %d\n", status2);
275 status = status2; /* FIXME: convert status? */
276 break;
279 RpcBindingFree(&handle);
281 for (i = 0; i < BindingVector->Count; i++)
283 unsigned j;
284 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
285 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
288 HeapFree(GetProcessHeap(), 0, entries);
290 return status;
293 /***********************************************************************
294 * RpcEpRegisterA (RPCRT4.@)
296 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
297 UUID_VECTOR *UuidVector, RPC_CSTR Annotation )
299 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, TRUE);
302 /***********************************************************************
303 * RpcEpRegisterNoReplaceA (RPCRT4.@)
305 RPC_STATUS WINAPI RpcEpRegisterNoReplaceA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
306 UUID_VECTOR *UuidVector, RPC_CSTR Annotation )
308 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, FALSE);
311 /***********************************************************************
312 * RpcEpRegisterW (RPCRT4.@)
314 RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
315 UUID_VECTOR *UuidVector, RPC_WSTR Annotation )
317 LPSTR annA = RPCRT4_strdupWtoA(Annotation);
318 RPC_STATUS status;
320 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, TRUE);
322 HeapFree(GetProcessHeap(), 0, annA);
323 return status;
326 /***********************************************************************
327 * RpcEpRegisterNoReplaceW (RPCRT4.@)
329 RPC_STATUS WINAPI RpcEpRegisterNoReplaceW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
330 UUID_VECTOR *UuidVector, RPC_WSTR Annotation )
332 LPSTR annA = RPCRT4_strdupWtoA(Annotation);
333 RPC_STATUS status;
335 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, FALSE);
337 HeapFree(GetProcessHeap(), 0, annA);
338 return status;
341 /***********************************************************************
342 * RpcEpUnregister (RPCRT4.@)
344 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
345 UUID_VECTOR *UuidVector )
347 PRPC_SERVER_INTERFACE If = IfSpec;
348 ULONG i;
349 RPC_STATUS status = RPC_S_OK;
350 error_status_t status2;
351 ept_entry_t *entries;
352 handle_t handle;
354 TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector);
355 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
356 for (i=0; i<BindingVector->Count; i++) {
357 RpcBinding* bind = BindingVector->BindingH[i];
358 TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq));
359 TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint));
361 if (UuidVector) {
362 for (i=0; i<UuidVector->Count; i++)
363 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
366 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
367 if (!entries)
368 return RPC_S_OUT_OF_MEMORY;
370 status = get_epm_handle_server(&handle);
371 if (status != RPC_S_OK)
373 HeapFree(GetProcessHeap(), 0, entries);
374 return status;
377 for (i = 0; i < BindingVector->Count; i++)
379 unsigned j;
380 RpcBinding* bind = BindingVector->BindingH[i];
381 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
383 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
384 bind->Protseq, bind->Endpoint,
385 bind->NetworkAddr,
386 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
387 if (status != RPC_S_OK) break;
389 if (UuidVector)
390 memcpy(&entries[i * UuidVector->Count + j].object, &UuidVector->Uuid[j], sizeof(GUID));
391 else
392 memset(&entries[i].object, 0, sizeof(entries[i].object));
396 if (status == RPC_S_OK)
398 __TRY
400 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
401 entries, TRUE, &status2);
403 __EXCEPT(rpc_filter)
405 status2 = GetExceptionCode();
407 __ENDTRY
408 if (status2 == RPC_S_SERVER_UNAVAILABLE)
409 status2 = EPT_S_NOT_REGISTERED;
410 if (status2 != RPC_S_OK)
411 ERR("ept_insert failed with error %d\n", status2);
412 status = status2; /* FIXME: convert status? */
414 RpcBindingFree(&handle);
416 for (i = 0; i < BindingVector->Count; i++)
418 unsigned j;
419 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
420 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
423 HeapFree(GetProcessHeap(), 0, entries);
425 return status;
428 /***********************************************************************
429 * RpcEpResolveBinding (RPCRT4.@)
431 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec )
433 PRPC_CLIENT_INTERFACE If = IfSpec;
434 RpcBinding* bind = Binding;
435 RPC_STATUS status;
436 error_status_t status2;
437 handle_t handle;
438 ept_lookup_handle_t entry_handle = NULL;
439 twr_t *tower;
440 twr_t *towers[4] = { NULL };
441 unsigned32 num_towers, i;
442 GUID uuid = GUID_NULL;
443 char *resolved_endpoint = NULL;
445 TRACE("(%p,%p)\n", Binding, IfSpec);
446 TRACE(" protseq=%s\n", debugstr_a(bind->Protseq));
447 TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid));
448 TRACE(" networkaddr=%s\n", debugstr_a(bind->NetworkAddr));
449 TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
451 /* just return for fully bound handles */
452 if (bind->Endpoint && (bind->Endpoint[0] != '\0'))
453 return RPC_S_OK;
455 status = get_epm_handle_client(Binding, &handle);
456 if (status != RPC_S_OK) return status;
458 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq,
459 ((RpcBinding *)handle)->Endpoint,
460 bind->NetworkAddr, &tower);
461 if (status != RPC_S_OK)
463 WARN("couldn't get tower\n");
464 RpcBindingFree(&handle);
465 return status;
468 while (TRUE)
470 __TRY
472 ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2);
473 /* FIXME: translate status2? */
475 __EXCEPT(rpc_filter)
477 status2 = GetExceptionCode();
479 __ENDTRY
480 if (status2 == RPC_S_SERVER_UNAVAILABLE &&
481 is_epm_destination_local(handle))
483 if (start_rpcss())
484 continue;
486 break;
489 RpcBindingFree(&handle);
490 I_RpcFree(tower);
492 if (status2 != RPC_S_OK)
494 ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), bind->Protseq, bind->NetworkAddr);
495 return status2;
498 for (i = 0; i < num_towers; i++)
500 /* only parse the tower if we haven't already found a suitable
501 * endpoint, otherwise just free the tower */
502 if (!resolved_endpoint)
504 status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL);
505 TRACE("status = %d\n", status);
507 I_RpcFree(towers[i]);
510 if (resolved_endpoint)
512 RPCRT4_ResolveBinding(Binding, resolved_endpoint);
513 I_RpcFree(resolved_endpoint);
514 return RPC_S_OK;
517 WARN("couldn't find an endpoint\n");
518 return EPT_S_NOT_REGISTERED;
521 /*****************************************************************************
522 * TowerExplode (RPCRT4.@)
524 RPC_STATUS WINAPI TowerExplode(
525 const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax,
526 char **protseq, char **endpoint, char **address)
528 size_t tower_size;
529 RPC_STATUS status;
530 const unsigned char *p;
531 u_int16 floor_count;
532 const twr_uuid_floor_t *object_floor;
533 const twr_uuid_floor_t *syntax_floor;
535 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower, object, syntax, protseq,
536 endpoint, address);
538 if (protseq)
539 *protseq = NULL;
540 if (endpoint)
541 *endpoint = NULL;
542 if (address)
543 *address = NULL;
545 tower_size = tower->tower_length;
547 if (tower_size < sizeof(u_int16))
548 return EPT_S_NOT_REGISTERED;
550 p = &tower->tower_octet_string[0];
552 floor_count = *(const u_int16 *)p;
553 p += sizeof(u_int16);
554 tower_size -= sizeof(u_int16);
555 TRACE("floor_count: %d\n", floor_count);
556 /* FIXME: should we do something with the floor count? at the moment we don't */
558 if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor))
559 return EPT_S_NOT_REGISTERED;
561 object_floor = (const twr_uuid_floor_t *)p;
562 p += sizeof(*object_floor);
563 tower_size -= sizeof(*object_floor);
564 syntax_floor = (const twr_uuid_floor_t *)p;
565 p += sizeof(*syntax_floor);
566 tower_size -= sizeof(*syntax_floor);
568 if ((object_floor->count_lhs != sizeof(object_floor->protid) +
569 sizeof(object_floor->uuid) + sizeof(object_floor->major_version)) ||
570 (object_floor->protid != EPM_PROTOCOL_UUID) ||
571 (object_floor->count_rhs != sizeof(object_floor->minor_version)))
572 return EPT_S_NOT_REGISTERED;
574 if ((syntax_floor->count_lhs != sizeof(syntax_floor->protid) +
575 sizeof(syntax_floor->uuid) + sizeof(syntax_floor->major_version)) ||
576 (syntax_floor->protid != EPM_PROTOCOL_UUID) ||
577 (syntax_floor->count_rhs != sizeof(syntax_floor->minor_version)))
578 return EPT_S_NOT_REGISTERED;
580 status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint);
581 if ((status == RPC_S_OK) && syntax && object)
583 syntax->SyntaxGUID = syntax_floor->uuid;
584 syntax->SyntaxVersion.MajorVersion = syntax_floor->major_version;
585 syntax->SyntaxVersion.MinorVersion = syntax_floor->minor_version;
586 object->SyntaxGUID = object_floor->uuid;
587 object->SyntaxVersion.MajorVersion = object_floor->major_version;
588 object->SyntaxVersion.MinorVersion = object_floor->minor_version;
590 return status;
593 /***********************************************************************
594 * TowerConstruct (RPCRT4.@)
596 RPC_STATUS WINAPI TowerConstruct(
597 const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax,
598 const char *protseq, const char *endpoint, const char *address,
599 twr_t **tower)
601 size_t tower_size;
602 RPC_STATUS status;
603 unsigned char *p;
604 twr_uuid_floor_t *object_floor;
605 twr_uuid_floor_t *syntax_floor;
607 TRACE("(%p, %p, %s, %s, %s, %p)\n", object, syntax, debugstr_a(protseq),
608 debugstr_a(endpoint), debugstr_a(address), tower);
610 *tower = NULL;
612 status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint);
614 if (status != RPC_S_OK)
615 return status;
617 tower_size += sizeof(u_int16) + sizeof(*object_floor) + sizeof(*syntax_floor);
618 *tower = I_RpcAllocate(FIELD_OFFSET(twr_t, tower_octet_string[tower_size]));
619 if (!*tower)
620 return RPC_S_OUT_OF_RESOURCES;
622 (*tower)->tower_length = tower_size;
623 p = &(*tower)->tower_octet_string[0];
624 *(u_int16 *)p = 5; /* number of floors */
625 p += sizeof(u_int16);
626 object_floor = (twr_uuid_floor_t *)p;
627 p += sizeof(*object_floor);
628 syntax_floor = (twr_uuid_floor_t *)p;
629 p += sizeof(*syntax_floor);
631 object_floor->count_lhs = sizeof(object_floor->protid) + sizeof(object_floor->uuid) +
632 sizeof(object_floor->major_version);
633 object_floor->protid = EPM_PROTOCOL_UUID;
634 object_floor->count_rhs = sizeof(object_floor->minor_version);
635 object_floor->uuid = object->SyntaxGUID;
636 object_floor->major_version = object->SyntaxVersion.MajorVersion;
637 object_floor->minor_version = object->SyntaxVersion.MinorVersion;
639 syntax_floor->count_lhs = sizeof(syntax_floor->protid) + sizeof(syntax_floor->uuid) +
640 sizeof(syntax_floor->major_version);
641 syntax_floor->protid = EPM_PROTOCOL_UUID;
642 syntax_floor->count_rhs = sizeof(syntax_floor->minor_version);
643 syntax_floor->uuid = syntax->SyntaxGUID;
644 syntax_floor->major_version = syntax->SyntaxVersion.MajorVersion;
645 syntax_floor->minor_version = syntax->SyntaxVersion.MinorVersion;
647 status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint);
648 if (status != RPC_S_OK)
650 I_RpcFree(*tower);
651 *tower = NULL;
652 return status;
654 return RPC_S_OK;
657 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
659 return HeapAlloc(GetProcessHeap(), 0, len);
662 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
664 HeapFree(GetProcessHeap(), 0, ptr);