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 #include "winsvc.h" 29 30 #include "rpc.h" 31 32 #include "wine/debug.h" 33 #include "wine/exception.h" 34 35 #include "rpc_binding.h" 36 #include "epm_c.h" 37 #include "epm_towers.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(ole); 40 41 /* The "real" RPC portmapper endpoints that I know of are: 42 * 43 * ncadg_ip_udp: 135 44 * ncacn_ip_tcp: 135 45 * ncacn_np: \\pipe\epmapper 46 * ncalrpc: epmapper 47 * ncacn_http: 593 48 * 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) 60 * 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... 64 */ 65 66 static const struct epm_endpoints 67 { 68 const char *protseq; 69 const char *endpoint; 70 } epm_endpoints[] = 71 { 72 { "ncacn_np", "\\pipe\\epmapper" }, 73 { "ncacn_ip_tcp", "135" }, 74 { "ncacn_ip_udp", "135" }, 75 { "ncalrpc", "epmapper" }, 76 { "ncacn_http", "593" }, 77 }; 78 79 static BOOL start_rpcss(void) 80 { 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; 85 86 TRACE("\n"); 87 88 if (!(scm = OpenSCManagerW( NULL, NULL, 0 ))) 89 { 90 ERR( "failed to open service manager\n" ); 91 return FALSE; 92 } 93 if (!(service = OpenServiceW( scm, rpcssW, SERVICE_START | SERVICE_QUERY_STATUS ))) 94 { 95 ERR( "failed to open RpcSs service\n" ); 96 CloseServiceHandle( scm ); 97 return FALSE; 98 } 99 if (StartServiceW( service, 0, NULL ) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) 100 { 101 ULONGLONG start_time = GetTickCount64(); 102 do 103 { 104 DWORD dummy; 105 106 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, 107 (BYTE *)&status, sizeof(status), &dummy )) 108 break; 109 if (status.dwCurrentState == SERVICE_RUNNING) 110 { 111 ret = TRUE; 112 break; 113 } 114 if (GetTickCount64() - start_time > 30000) break; 115 Sleep( 100 ); 116 117 } while (status.dwCurrentState == SERVICE_START_PENDING); 118 119 if (status.dwCurrentState != SERVICE_RUNNING) 120 WARN( "RpcSs failed to start %u\n", status.dwCurrentState ); 121 } 122 else ERR( "failed to start RpcSs service\n" ); 123 124 CloseServiceHandle( service ); 125 CloseServiceHandle( scm ); 126 return ret; 127 } 128 129 static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) 130 { 131 RpcBinding *bind = handle; 132 const char *protseq = bind->Protseq; 133 const char *network_addr = bind->NetworkAddr; 134 135 return (!strcmp(protseq, "ncalrpc") || 136 (!strcmp(protseq, "ncacn_np") && 137 (!network_addr || !strcmp(network_addr, ".")))); 138 } 139 140 static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle) 141 { 142 RpcBinding *bind = handle; 143 const char * pszEndpoint = NULL; 144 RPC_STATUS status; 145 RpcBinding* epm_bind; 146 unsigned int i; 147 148 if (bind->server) 149 return RPC_S_INVALID_BINDING; 150 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; 154 155 if (!pszEndpoint) 156 { 157 FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq)); 158 return RPC_S_PROTSEQ_NOT_SUPPORTED; 159 } 160 161 status = RpcBindingCopy(handle, epm_handle); 162 if (status != RPC_S_OK) return status; 163 164 epm_bind = *epm_handle; 165 if (epm_bind->AuthInfo) 166 { 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; 171 } 172 RPCRT4_ResolveBinding(epm_bind, pszEndpoint); 173 TRACE("RPC_S_OK\n"); 174 return RPC_S_OK; 175 } 176 177 static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle) 178 { 179 unsigned char string_binding[] = "ncacn_np:.[\\\\pipe\\\\epmapper]"; 180 181 return RpcBindingFromStringBindingA(string_binding, epm_handle); 182 } 183 184 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr) 185 { 186 switch (__eptr->ExceptionRecord->ExceptionCode) 187 { 188 case EXCEPTION_ACCESS_VIOLATION: 189 case EXCEPTION_ILLEGAL_INSTRUCTION: 190 return EXCEPTION_CONTINUE_SEARCH; 191 default: 192 return EXCEPTION_EXECUTE_HANDLER; 193 } 194 } 195 196 static RPC_STATUS epm_register( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 197 UUID_VECTOR *UuidVector, RPC_CSTR Annotation, BOOL replace ) 198 { 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; 205 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)); 212 } 213 if (UuidVector) { 214 for (i=0; i<UuidVector->Count; i++) 215 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); 216 } 217 218 if (!BindingVector->Count) return RPC_S_OK; 219 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; 223 224 status = get_epm_handle_server(&handle); 225 if (status != RPC_S_OK) 226 { 227 HeapFree(GetProcessHeap(), 0, entries); 228 return status; 229 } 230 231 for (i = 0; i < BindingVector->Count; i++) 232 { 233 unsigned j; 234 RpcBinding* bind = BindingVector->BindingH[i]; 235 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 236 { 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; 242 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)); 250 } 251 } 252 253 if (status == RPC_S_OK) 254 { 255 while (TRUE) 256 { 257 __TRY 258 { 259 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1), 260 entries, replace, &status2); 261 } 262 __EXCEPT(rpc_filter) 263 { 264 status2 = GetExceptionCode(); 265 } 266 __ENDTRY 267 if (status2 == RPC_S_SERVER_UNAVAILABLE && 268 is_epm_destination_local(handle)) 269 { 270 if (start_rpcss()) 271 continue; 272 } 273 if (status2 != RPC_S_OK) 274 ERR("ept_insert failed with error %d\n", status2); 275 status = status2; /* FIXME: convert status? */ 276 break; 277 } 278 } 279 RpcBindingFree(&handle); 280 281 for (i = 0; i < BindingVector->Count; i++) 282 { 283 unsigned j; 284 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 285 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 286 } 287 288 HeapFree(GetProcessHeap(), 0, entries); 289 290 return status; 291 } 292 293 /*********************************************************************** 294 * RpcEpRegisterA (RPCRT4.@) 295 */ 296 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 297 UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) 298 { 299 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, TRUE); 300 } 301 302 /*********************************************************************** 303 * RpcEpRegisterNoReplaceA (RPCRT4.@) 304 */ 305 RPC_STATUS WINAPI RpcEpRegisterNoReplaceA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 306 UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) 307 { 308 return epm_register(IfSpec, BindingVector, UuidVector, Annotation, FALSE); 309 } 310 311 /*********************************************************************** 312 * RpcEpRegisterW (RPCRT4.@) 313 */ 314 RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 315 UUID_VECTOR *UuidVector, RPC_WSTR Annotation ) 316 { 317 LPSTR annA = RPCRT4_strdupWtoA(Annotation); 318 RPC_STATUS status; 319 320 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, TRUE); 321 322 HeapFree(GetProcessHeap(), 0, annA); 323 return status; 324 } 325 326 /*********************************************************************** 327 * RpcEpRegisterNoReplaceW (RPCRT4.@) 328 */ 329 RPC_STATUS WINAPI RpcEpRegisterNoReplaceW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 330 UUID_VECTOR *UuidVector, RPC_WSTR Annotation ) 331 { 332 LPSTR annA = RPCRT4_strdupWtoA(Annotation); 333 RPC_STATUS status; 334 335 status = epm_register(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA, FALSE); 336 337 HeapFree(GetProcessHeap(), 0, annA); 338 return status; 339 } 340 341 /*********************************************************************** 342 * RpcEpUnregister (RPCRT4.@) 343 */ 344 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, 345 UUID_VECTOR *UuidVector ) 346 { 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; 353 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)); 360 } 361 if (UuidVector) { 362 for (i=0; i<UuidVector->Count; i++) 363 TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); 364 } 365 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; 369 370 status = get_epm_handle_server(&handle); 371 if (status != RPC_S_OK) 372 { 373 HeapFree(GetProcessHeap(), 0, entries); 374 return status; 375 } 376 377 for (i = 0; i < BindingVector->Count; i++) 378 { 379 unsigned j; 380 RpcBinding* bind = BindingVector->BindingH[i]; 381 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 382 { 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; 388 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)); 393 } 394 } 395 396 if (status == RPC_S_OK) 397 { 398 __TRY 399 { 400 ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1), 401 entries, TRUE, &status2); 402 } 403 __EXCEPT(rpc_filter) 404 { 405 status2 = GetExceptionCode(); 406 } 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? */ 413 } 414 RpcBindingFree(&handle); 415 416 for (i = 0; i < BindingVector->Count; i++) 417 { 418 unsigned j; 419 for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) 420 I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower); 421 } 422 423 HeapFree(GetProcessHeap(), 0, entries); 424 425 return status; 426 } 427 428 /*********************************************************************** 429 * RpcEpResolveBinding (RPCRT4.@) 430 */ 431 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) 432 { 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; 444 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)); 450 451 /* just return for fully bound handles */ 452 if (bind->Endpoint && (bind->Endpoint[0] != '\0')) 453 return RPC_S_OK; 454 455 status = get_epm_handle_client(Binding, &handle); 456 if (status != RPC_S_OK) return status; 457 458 status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq, 459 ((RpcBinding *)handle)->Endpoint, 460 bind->NetworkAddr, &tower); 461 if (status != RPC_S_OK) 462 { 463 WARN("couldn't get tower\n"); 464 RpcBindingFree(&handle); 465 return status; 466 } 467 468 while (TRUE) 469 { 470 __TRY 471 { 472 ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2); 473 /* FIXME: translate status2? */ 474 } 475 __EXCEPT(rpc_filter) 476 { 477 status2 = GetExceptionCode(); 478 } 479 __ENDTRY 480 if (status2 == RPC_S_SERVER_UNAVAILABLE && 481 is_epm_destination_local(handle)) 482 { 483 if (start_rpcss()) 484 continue; 485 } 486 break; 487 }; 488 489 RpcBindingFree(&handle); 490 I_RpcFree(tower); 491 492 if (status2 != RPC_S_OK) 493 { 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; 496 } 497 498 for (i = 0; i < num_towers; i++) 499 { 500 /* only parse the tower if we haven't already found a suitable 501 * endpoint, otherwise just free the tower */ 502 if (!resolved_endpoint) 503 { 504 status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL); 505 TRACE("status = %d\n", status); 506 } 507 I_RpcFree(towers[i]); 508 } 509 510 if (resolved_endpoint) 511 { 512 RPCRT4_ResolveBinding(Binding, resolved_endpoint); 513 I_RpcFree(resolved_endpoint); 514 return RPC_S_OK; 515 } 516 517 WARN("couldn't find an endpoint\n"); 518 return EPT_S_NOT_REGISTERED; 519 } 520 521 /***************************************************************************** 522 * TowerExplode (RPCRT4.@) 523 */ 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) 527 { 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; 534 535 TRACE("(%p, %p, %p, %p, %p, %p)\n", tower, object, syntax, protseq, 536 endpoint, address); 537 538 if (protseq) 539 *protseq = NULL; 540 if (endpoint) 541 *endpoint = NULL; 542 if (address) 543 *address = NULL; 544 545 tower_size = tower->tower_length; 546 547 if (tower_size < sizeof(u_int16)) 548 return EPT_S_NOT_REGISTERED; 549 550 p = &tower->tower_octet_string[0]; 551 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 */ 557 558 if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor)) 559 return EPT_S_NOT_REGISTERED; 560 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); 567 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; 573 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; 579 580 status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint); 581 if ((status == RPC_S_OK) && syntax && object) 582 { 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; 589 } 590 return status; 591 } 592 593 /*********************************************************************** 594 * TowerConstruct (RPCRT4.@) 595 */ 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) 600 { 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; 606 607 TRACE("(%p, %p, %s, %s, %s, %p)\n", object, syntax, debugstr_a(protseq), 608 debugstr_a(endpoint), debugstr_a(address), tower); 609 610 *tower = NULL; 611 612 status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint); 613 614 if (status != RPC_S_OK) 615 return status; 616 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; 621 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); 630 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; 638 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; 646 647 status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint); 648 if (status != RPC_S_OK) 649 { 650 I_RpcFree(*tower); 651 *tower = NULL; 652 return status; 653 } 654 return RPC_S_OK; 655 } 656 657 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len) 658 { 659 return HeapAlloc(GetProcessHeap(), 0, len); 660 } 661 662 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) 663 { 664 HeapFree(GetProcessHeap(), 0, ptr); 665 } 666