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 "precomp.h" 24 25 #include <winsvc.h> 26 27 #include "epm_towers.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(ole); 30 31 /* The "real" RPC portmapper endpoints that I know of are: 32 * 33 * ncadg_ip_udp: 135 34 * ncacn_ip_tcp: 135 35 * ncacn_np: \\pipe\epmapper 36 * ncalrpc: epmapper 37 * ncacn_http: 593 38 * 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) 50 * 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... 54 */ 55 56 static const struct epm_endpoints 57 { 58 const char *protseq; 59 const char *endpoint; 60 } epm_endpoints[] = 61 { 62 { "ncacn_np", "\\pipe\\epmapper" }, 63 { "ncacn_ip_tcp", "135" }, 64 { "ncacn_ip_udp", "135" }, 65 { "ncalrpc", "epmapper" }, 66 { "ncacn_http", "593" }, 67 }; 68 69 static BOOL start_rpcss(void) 70 { 71 static const WCHAR rpcssW[] = {'R','p','c','S','s',0}; 72 SC_HANDLE scm, service; 73 SERVICE_STATUS_PROCESS status; 74 BOOL ret = FALSE; 75 76 TRACE("\n"); 77 78 if (!(scm = OpenSCManagerW( NULL, NULL, 0 ))) 79 { 80 ERR( "failed to open service manager\n" ); 81 return FALSE; 82 } 83 if (!(service = OpenServiceW( scm, rpcssW, SERVICE_START | SERVICE_QUERY_STATUS ))) 84 { 85 ERR( "failed to open RpcSs service\n" ); 86 CloseServiceHandle( scm ); 87 return FALSE; 88 } 89 if (StartServiceW( service, 0, NULL ) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) 90 { 91 ULONGLONG start_time = GetTickCount64(); 92 do 93 { 94 DWORD dummy; 95 96 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, 97 (BYTE *)&status, sizeof(status), &dummy )) 98 break; 99 if (status.dwCurrentState == SERVICE_RUNNING) 100 { 101 ret = TRUE; 102 break; 103 } 104 if (GetTickCount64() - start_time > 30000) break; 105 Sleep( 100 ); 106 107 } while (status.dwCurrentState == SERVICE_START_PENDING); 108 109 if (status.dwCurrentState != SERVICE_RUNNING) 110 WARN( "RpcSs failed to start %u\n", status.dwCurrentState ); 111 } 112 else ERR( "failed to start RpcSs service\n" ); 113 114 CloseServiceHandle( service ); 115 CloseServiceHandle( scm ); 116 return ret; 117 } 118 119 static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) 120 { 121 RpcBinding *bind = handle; 122 const char *protseq = bind->Protseq; 123 const char *network_addr = bind->NetworkAddr; 124 125 return (!strcmp(protseq, "ncalrpc") || 126 (!strcmp(protseq, "ncacn_np") && 127 (!network_addr || !strcmp(network_addr, ".")))); 128 } 129 130 static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle) 131 { 132 RpcBinding *bind = handle; 133 const char * pszEndpoint = NULL; 134 RPC_STATUS status; 135 RpcBinding* epm_bind; 136 unsigned int i; 137 138 if (bind->server) 139 return RPC_S_INVALID_BINDING; 140 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; 144 145 if (!pszEndpoint) 146 { 147 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq)); 148 return RPC_S_PROTSEQ_NOT_SUPPORTED; 149 } 150 151 status = RpcBindingCopy(handle, epm_handle); 152 if (status != RPC_S_OK) return status; 153 154 epm_bind = *epm_handle; 155 if (epm_bind->AuthInfo) 156 { 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; 161 } 162 RPCRT4_ResolveBinding(epm_bind, pszEndpoint); 163 TRACE("RPC_S_OK\n"); 164 return RPC_S_OK; 165 } 166 167 static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle) 168 { 169 unsigned char string_binding[] = "ncacn_np:.[\\\\pipe\\\\epmapper]"; 170 171 return RpcBindingFromStringBindingA(string_binding, epm_handle); 172 } 173 174 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr) 175 { 176 switch (__eptr->ExceptionRecord->ExceptionCode) 177 { 178 case EXCEPTION_ACCESS_VIOLATION: 179 case EXCEPTION_ILLEGAL_INSTRUCTION: 180 return EXCEPTION_CONTINUE_SEARCH; 181 default: 182 return EXCEPTION_EXECUTE_HANDLER; 183 } 184 } 185 186 static RPC_STATUS epm_register( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 187 UUID_VECTOR *UuidVector, RPC_CSTR Annotation, BOOL replace ) 188 { 189 PRPC_SERVER_INTERFACE If = IfSpec; 190 ULONG i; 191 RPC_STATUS status = RPC_S_OK; 192 error_status_t status2; 193 ept_entry_t *entries; 194 handle_t handle; 195 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)); 202 } 203 if (UuidVector) { 204 for (i=0; i<UuidVector->Count; i++) 205 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); 206 } 207 208 if (!BindingVector->Count) return RPC_S_OK; 209 210 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1)); 211 if (!entries) 212 return RPC_S_OUT_OF_MEMORY; 213 214 status = get_epm_handle_server(&handle); 215 if (status != RPC_S_OK) 216 { 217 HeapFree(GetProcessHeap(), 0, entries); 218 return status; 219 } 220 221 for (i = 0; i < BindingVector->Count; i++) 222 { 223 unsigned j; 224 RpcBinding* bind = BindingVector->BindingH[i]; 225 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 226 { 227 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, 228 bind->Protseq, bind->Endpoint, 229 bind->NetworkAddr, 230 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 231 if (status != RPC_S_OK) break; 232 233 if (UuidVector) 234 memcpy(&entries[i * UuidVector->Count].object, &UuidVector->Uuid[j], sizeof(GUID)); 235 else 236 memset(&entries[i].object, 0, sizeof(entries[i].object)); 237 if (Annotation) 238 memcpy(entries[i].annotation, Annotation, 239 min(strlen((char *)Annotation) + 1, ept_max_annotation_size)); 240 } 241 } 242 243 if (status == RPC_S_OK) 244 { 245 while (TRUE) 246 { 247 __TRY 248 { 249 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1), 250 entries, replace, &status2); 251 } 252 __EXCEPT(rpc_filter) 253 { 254 status2 = GetExceptionCode(); 255 } 256 __ENDTRY 257 if (status2 == RPC_S_SERVER_UNAVAILABLE && 258 is_epm_destination_local(handle)) 259 { 260 if (start_rpcss()) 261 continue; 262 } 263 if (status2 != RPC_S_OK) 264 ERR("ept_insert failed with error %d\n", status2); 265 status = status2; /* FIXME: convert status? */ 266 break; 267 } 268 } 269 RpcBindingFree(&handle); 270 271 for (i = 0; i < BindingVector->Count; i++) 272 { 273 unsigned j; 274 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 275 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 276 } 277 278 HeapFree(GetProcessHeap(), 0, entries); 279 280 return status; 281 } 282 283 /*********************************************************************** 284 * RpcEpRegisterA (RPCRT4.@) 285 */ 286 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 287 UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) 288 { 289 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, TRUE); 290 } 291 292 /*********************************************************************** 293 * RpcEpRegisterNoReplaceA (RPCRT4.@) 294 */ 295 RPC_STATUS WINAPI RpcEpRegisterNoReplaceA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 296 UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) 297 { 298 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, FALSE); 299 } 300 301 /*********************************************************************** 302 * RpcEpRegisterW (RPCRT4.@) 303 */ 304 RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 305 UUID_VECTOR *UuidVector, RPC_WSTR Annotation ) 306 { 307 LPSTR annA = RPCRT4_strdupWtoA(Annotation); 308 RPC_STATUS status; 309 310 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, TRUE); 311 312 HeapFree(GetProcessHeap(), 0, annA); 313 return status; 314 } 315 316 /*********************************************************************** 317 * RpcEpRegisterNoReplaceW (RPCRT4.@) 318 */ 319 RPC_STATUS WINAPI RpcEpRegisterNoReplaceW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 320 UUID_VECTOR *UuidVector, RPC_WSTR Annotation ) 321 { 322 LPSTR annA = RPCRT4_strdupWtoA(Annotation); 323 RPC_STATUS status; 324 325 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, FALSE); 326 327 HeapFree(GetProcessHeap(), 0, annA); 328 return status; 329 } 330 331 /*********************************************************************** 332 * RpcEpUnregister (RPCRT4.@) 333 */ 334 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 335 UUID_VECTOR *UuidVector ) 336 { 337 PRPC_SERVER_INTERFACE If = IfSpec; 338 ULONG i; 339 RPC_STATUS status = RPC_S_OK; 340 error_status_t status2; 341 ept_entry_t *entries; 342 handle_t handle; 343 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)); 350 } 351 if (UuidVector) { 352 for (i=0; i<UuidVector->Count; i++) 353 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); 354 } 355 356 entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1)); 357 if (!entries) 358 return RPC_S_OUT_OF_MEMORY; 359 360 status = get_epm_handle_server(&handle); 361 if (status != RPC_S_OK) 362 { 363 HeapFree(GetProcessHeap(), 0, entries); 364 return status; 365 } 366 367 for (i = 0; i < BindingVector->Count; i++) 368 { 369 unsigned j; 370 RpcBinding* bind = BindingVector->BindingH[i]; 371 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 372 { 373 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, 374 bind->Protseq, bind->Endpoint, 375 bind->NetworkAddr, 376 &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 377 if (status != RPC_S_OK) break; 378 379 if (UuidVector) 380 memcpy(&entries[i * UuidVector->Count + j].object, &UuidVector->Uuid[j], sizeof(GUID)); 381 else 382 memset(&entries[i].object, 0, sizeof(entries[i].object)); 383 } 384 } 385 386 if (status == RPC_S_OK) 387 { 388 __TRY 389 { 390 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1), 391 entries, TRUE, &status2); 392 } 393 __EXCEPT(rpc_filter) 394 { 395 status2 = GetExceptionCode(); 396 } 397 __ENDTRY 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? */ 403 } 404 RpcBindingFree(&handle); 405 406 for (i = 0; i < BindingVector->Count; i++) 407 { 408 unsigned j; 409 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 410 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 411 } 412 413 HeapFree(GetProcessHeap(), 0, entries); 414 415 return status; 416 } 417 418 /*********************************************************************** 419 * RpcEpResolveBinding (RPCRT4.@) 420 */ 421 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) 422 { 423 PRPC_CLIENT_INTERFACE If = IfSpec; 424 RpcBinding* bind = Binding; 425 RPC_STATUS status; 426 error_status_t status2; 427 handle_t handle; 428 ept_lookup_handle_t entry_handle = NULL; 429 twr_t *tower; 430 twr_t *towers[4] = { NULL }; 431 unsigned32 num_towers, i; 432 GUID uuid = GUID_NULL; 433 char *resolved_endpoint = NULL; 434 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)); 440 441 /* just return for fully bound handles */ 442 if (bind->Endpoint && (bind->Endpoint[0] != '\0')) 443 return RPC_S_OK; 444 445 status = get_epm_handle_client(Binding, &handle); 446 if (status != RPC_S_OK) return status; 447 448 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq, 449 ((RpcBinding *)handle)->Endpoint, 450 bind->NetworkAddr, &tower); 451 if (status != RPC_S_OK) 452 { 453 WARN("couldn't get tower\n"); 454 RpcBindingFree(&handle); 455 return status; 456 } 457 458 while (TRUE) 459 { 460 __TRY 461 { 462 ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2); 463 /* FIXME: translate status2? */ 464 } 465 __EXCEPT(rpc_filter) 466 { 467 status2 = GetExceptionCode(); 468 } 469 __ENDTRY 470 if (status2 == RPC_S_SERVER_UNAVAILABLE && 471 is_epm_destination_local(handle)) 472 { 473 if (start_rpcss()) 474 continue; 475 } 476 break; 477 }; 478 479 RpcBindingFree(&handle); 480 I_RpcFree(tower); 481 482 if (status2 != RPC_S_OK) 483 { 484 ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), bind->Protseq, bind->NetworkAddr); 485 return status2; 486 } 487 488 for (i = 0; i < num_towers; i++) 489 { 490 /* only parse the tower if we haven't already found a suitable 491 * endpoint, otherwise just free the tower */ 492 if (!resolved_endpoint) 493 { 494 status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL); 495 TRACE("status = %d\n", status); 496 } 497 I_RpcFree(towers[i]); 498 } 499 500 if (resolved_endpoint) 501 { 502 RPCRT4_ResolveBinding(Binding, resolved_endpoint); 503 I_RpcFree(resolved_endpoint); 504 return RPC_S_OK; 505 } 506 507 WARN("couldn't find an endpoint\n"); 508 return EPT_S_NOT_REGISTERED; 509 } 510 511 /***************************************************************************** 512 * TowerExplode (RPCRT4.@) 513 */ 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) 517 { 518 size_t tower_size; 519 RPC_STATUS status; 520 const unsigned char *p; 521 u_int16 floor_count; 522 const twr_uuid_floor_t *object_floor; 523 const twr_uuid_floor_t *syntax_floor; 524 525 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower, object, syntax, protseq, 526 endpoint, address); 527 528 if (protseq) 529 *protseq = NULL; 530 if (endpoint) 531 *endpoint = NULL; 532 if (address) 533 *address = NULL; 534 535 tower_size = tower->tower_length; 536 537 if (tower_size < sizeof(u_int16)) 538 return EPT_S_NOT_REGISTERED; 539 540 p = &tower->tower_octet_string[0]; 541 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 */ 547 548 if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor)) 549 return EPT_S_NOT_REGISTERED; 550 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); 557 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; 563 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; 569 570 status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint); 571 if ((status == RPC_S_OK) && syntax && object) 572 { 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; 579 } 580 return status; 581 } 582 583 /*********************************************************************** 584 * TowerConstruct (RPCRT4.@) 585 */ 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, 589 twr_t **tower) 590 { 591 size_t tower_size; 592 RPC_STATUS status; 593 unsigned char *p; 594 twr_uuid_floor_t *object_floor; 595 twr_uuid_floor_t *syntax_floor; 596 597 TRACE("(%p, %p, %s, %s, %s, %p)\n", object, syntax, debugstr_a(protseq), 598 debugstr_a(endpoint), debugstr_a(address), tower); 599 600 *tower = NULL; 601 602 status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint); 603 604 if (status != RPC_S_OK) 605 return status; 606 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])); 609 if (!*tower) 610 return RPC_S_OUT_OF_RESOURCES; 611 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); 620 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; 628 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; 636 637 status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint); 638 if (status != RPC_S_OK) 639 { 640 I_RpcFree(*tower); 641 *tower = NULL; 642 return status; 643 } 644 return RPC_S_OK; 645 } 646 647 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len) 648 { 649 return HeapAlloc(GetProcessHeap(), 0, len); 650 } 651 652 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) 653 { 654 HeapFree(GetProcessHeap(), 0, ptr); 655 } 656