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