xref: /reactos/dll/win32/rpcrt4/rpc_epmap.c (revision c2c66aff)
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