1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      comep.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  These routines allow applications to manipulate information in the
90**  endpoint mapper database.
91**
92*/
93
94#include <commonp.h>    /* Common internals for RPC runtime system  */
95#include <com.h>        /* Externals for Common Services component  */
96#include <comp.h>       /* Private communications services */
97#include <dce/ep.h>     /* NIDL generated include for ep interface  */
98#include <comtwr.h>     /* Tower <=> Tower ref routines */
99#include <comtwrref.h>  /* Tower ref routines */
100#include <comtwrflr.h>  /* Tower floor routines */
101
102
103/*
104 * Number of compatible towers to be returned from ept_map in one call.
105 */
106#define MAX_TOWERS  15
107
108/*
109 * Magic cookie to check mgmt_ep inquiry_context.
110 */
111#define MGMT_EP_C_INQUIRY_CONTEXT   1234
112
113/*
114 * mgmt_ep inquiry context.
115 */
116
117#define MAX_ENTS    15
118
119typedef struct {
120    unsigned32              usage;
121    ndr_boolean             done;
122    rpc_binding_handle_t    ep_binding;
123    unsigned32              inquiry_type;
124    idl_uuid_t                  object;
125    rpc_if_id_t             if_id;
126    unsigned32              vers_option;
127    ept_lookup_handle_t     entry_handle;
128    unsigned32              num_ents;
129    unsigned32              next_ent;
130    ept_entry_t             entries[MAX_ENTS];
131} mgmt_ep_inq_rep_t, *mgmt_ep_inq_rep_p_t;
132
133INTERNAL void ep_register (
134        rpc_if_handle_t         ifspec,
135        rpc_binding_vector_t    *binding_vec,
136        uuid_vector_t           *object_uuid_vec,
137        unsigned_char_p_t       annotation,
138        boolean32               replace,
139        unsigned32              * /*status*/
140    );
141
142INTERNAL void get_ep_binding (
143        rpc_binding_handle_t    input_binding,
144        rpc_binding_handle_t    *output_binding,
145        unsigned32              * /*status*/
146    );
147
148INTERNAL void tower_to_if_id (
149        twr_p_t                 tower,
150        rpc_if_id_t             *if_id,
151        unsigned32              * /*status*/
152    );
153
154INTERNAL void ep_get_endpoint (
155       rpc_if_rep_p_t          if_r,
156       rpc_binding_rep_p_t     binding_r,
157       unsigned32              * /*st*/
158    );
159
160INTERNAL idl_void_p_t rpc__ep_mem_alloc (
161	idl_void_p_t /* context */,
162        idl_size_t  /*size*/
163    );
164
165INTERNAL void rpc__ep_mem_free (
166	idl_void_p_t /* context */,
167        dce_pointer_t  /*ptr*/
168    );
169
170
171/*
172**++
173**
174**  ROUTINE NAME:       rpc_ep_register
175**
176**  SCOPE:              PUBLIC - declared in rpc.idl
177**
178**  DESCRIPTION:
179**
180**  Adds server address information to the endpoint mapper database.
181**  A server routine calls this routine only if the server has dynamically
182**  generated endpoints.
183**
184**  INPUTS:
185**
186**      ifspec          Interface specification to register with the
187**                      endpoint mapper.
188**
189**      binding_vec     Vector of binding handles over which the server
190**                      can receive RPCs.
191**
192**      object_uuid_vec A vector of object UUIDs offered by the server.
193**                      The server application constructs this vector.
194**
195**      annotation      A character string comment applied to each cross-
196**                      product entry added to the endpoint mapper.
197**
198**  INPUTS/OUTPUTS:     none
199**
200**  OUTPUTS:
201**
202**      status          The result of the operation. One of:
203**                          rpc_s_ok
204**                          rpc_s_no_bindings
205**                          rpc_s_invalid_binding
206**
207**  IMPLICIT INPUTS:    none
208**
209**  IMPLICIT OUTPUTS:   none
210**
211**  FUNCTION VALUE:     void
212**
213**  SIDE EFFECTS:       none
214**
215**--
216**/
217
218PUBLIC void rpc_ep_register
219(
220    rpc_if_handle_t             ifspec,
221    rpc_binding_vector_t        *binding_vec,
222    uuid_vector_t               *object_uuid_vec,
223    unsigned_char_p_t           annotation,
224    unsigned32                  *status
225)
226{
227    ep_register (ifspec, binding_vec, object_uuid_vec, annotation, true, status);
228}
229
230/*
231**++
232**
233**  ROUTINE NAME:       rpc_ep_register_no_replace
234**
235**  SCOPE:              PUBLIC - declared in rpc.idl
236**
237**  DESCRIPTION:
238**
239**  Like rpc_ep_register, except doesn't replace any existing entries.
240**
241**  INPUTS:
242**
243**      ifspec          Interface specification to register with the
244**                      endpoint mapper.
245**
246**      binding_vec     Vector of binding handles over which the server
247**                      can receive RPCs.
248**
249**      object_uuid_vec A vector of object UUIDs offered by the server.
250**                      The server application constructs this vector.
251**
252**      annotation      A character string comment applied to each cross-
253**                      product entry added to the endpoint mapper.
254**
255**  INPUTS/OUTPUTS:     none
256**
257**  OUTPUTS:
258**
259**      status          The result of the operation. One of:
260**                          rpc_s_ok
261**                          rpc_s_no_bindings
262**                          rpc_s_invalid_binding
263**
264**  IMPLICIT INPUTS:    none
265**
266**  IMPLICIT OUTPUTS:   none
267**
268**  FUNCTION VALUE:     void
269**
270**  SIDE EFFECTS:       none
271**
272**--
273**/
274
275PUBLIC void rpc_ep_register_no_replace
276(
277    rpc_if_handle_t             ifspec,
278    rpc_binding_vector_t        *binding_vec,
279    uuid_vector_t               *object_uuid_vec,
280    unsigned_char_p_t           annotation,
281    unsigned32                  *status
282)
283{
284    ep_register (ifspec, binding_vec, object_uuid_vec, annotation, false, status);
285}
286
287/*
288**++
289**
290**  ROUTINE NAME:       ep_register
291**
292**  SCOPE:              INTERNAL
293**
294**  DESCRIPTION:
295**
296**  Common routine for rpc_ep_register*.
297**
298**  INPUTS:
299**
300**      ifspec          Interface specification to register with the
301**                      endpoint mapper.
302**
303**      binding_vec     Vector of binding handles over which the server
304**                      can receive RPCs.
305**
306**      object_uuid_vec A vector of object UUIDs offered by the server.
307**                      The server application constructs this vector.
308**
309**      annotation      A character string comment applied to each cross-
310**                      product entry added to the endpoint mapper.
311**
312**  INPUTS/OUTPUTS:     none
313**
314**  OUTPUTS:
315**
316**      status          The result of the operation. One of:
317**                          rpc_s_ok
318**                          rpc_s_no_interfaces
319**                          rpc_s_no_bindings
320**                          rpc_s_invalid_binding
321**
322**  IMPLICIT INPUTS:    none
323**
324**  IMPLICIT OUTPUTS:   none
325**
326**  FUNCTION VALUE:     void
327**
328**  SIDE EFFECTS:       none
329**
330**--
331**/
332
333INTERNAL void ep_register
334(
335    rpc_if_handle_t             ifspec,
336    rpc_binding_vector_t        *binding_vec,
337    uuid_vector_t               *object_uuid_vec,
338    unsigned_char_p_t           annotation,
339    boolean32                   replace,
340    unsigned32                  *status
341)
342{
343    ept_entry_t                 *ept_entry;
344    rpc_if_rep_p_t              if_rep = (rpc_if_rep_p_t) ifspec;
345    rpc_binding_handle_t        ep_binding = NULL;
346    unsigned32                  i, j;
347    unsigned32                  curr_hand = 0, curr_tower = 0, curr_obj = 0;
348    unsigned32                  st;
349    rpc_tower_ref_vector_p_t    tower_vec;
350
351    CODING_ERROR (status);
352    RPC_VERIFY_INIT ();
353
354    if (ifspec == NULL)
355    {
356        *status = rpc_s_no_interfaces;
357        return;
358    }
359
360    if (binding_vec == NULL || binding_vec->count == 0)
361    {
362        *status = rpc_s_no_bindings;
363        return;
364    }
365
366#ifndef __hpux__
367    /*
368     * First attempt to contact the local endpoint mapper with ncalrpc.
369     * This should work even if the network has not yet come up
370     */
371    rpc_binding_from_string_binding(
372        (unsigned_char_t*) "ncalrpc:[epmapper]",
373        &ep_binding,
374        status);
375
376    if (*status == rpc_s_ok)
377    {
378        if (!rpc_mgmt_is_server_listening(ep_binding, status))
379        {
380            rpc_binding_free(&ep_binding, status);
381            ep_binding = NULL;
382        }
383    }
384#endif
385
386    if (!ep_binding)
387    {
388        /*
389         * Spin through the binding vector array looking for a non-NULL pointer
390         * to a binding handle.  If one is found set curr_hand to its offset in
391         * the binding vector.
392         * Also check for a binding handle with no endpoint; if one is found
393         * return an error.
394         */
395
396        curr_hand = binding_vec->count;
397        for (i = 0; i < binding_vec->count; i++)
398        {
399            if (binding_vec->binding_h[i] != NULL)
400            {
401                rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_vec->binding_h[i];
402                if (binding_rep->addr_has_endpoint == false)
403                {
404                    *status = rpc_s_invalid_binding;
405                    return;
406                }
407
408#ifdef __hpux__
409                if (binding_rep->rpc_addr && binding_rep->rpc_addr->sa.family == RPC_C_NAF_ID_IP)
410                {
411                    struct sockaddr_in* addr = (struct sockaddr_in*) &binding_rep->rpc_addr->sa;
412                    unsigned char* addr_bytes = (unsigned char*) &addr->sin_addr.s_addr;
413
414                    /* Don't attempt to connect on the loopback interface on HP-UX
415                       because the ep mapper incorrectly rejects attempts to register
416                       mappings through it */
417                    if (addr_bytes[0] == 127)
418                    {
419                        continue;
420                    }
421                }
422
423                if (binding_rep->rpc_addr && binding_rep->rpc_addr->rpc_protseq_id == rpc_c_protseq_id_ncalrpc)
424                {
425                    /* Don't attempt to connect over ncalrpc on HP-UX because its native DCE
426                       implementation does not understand it */
427                    continue;
428                }
429#endif
430
431                curr_hand = i;
432                break;
433            }
434        }
435
436        /*
437         * If all the handles were NULL'd out, return an error.
438         */
439
440        if (curr_hand >= binding_vec->count)
441        {
442            *status = rpc_s_no_bindings;
443            return;
444        }
445
446        /*
447         * Otherwise, use the a valid handle to converse with the EP mapper.
448         */
449
450        get_ep_binding(binding_vec->binding_h[curr_hand], &ep_binding, status);
451        if (*status != rpc_s_ok)
452            return;
453    }
454
455    /*
456     * Allocate the EP entry structure to avoid taking up stack space.
457     */
458
459    RPC_MEM_ALLOC(ept_entry, ept_entry_t *, sizeof *ept_entry,
460            RPC_C_MEM_EPT_ENTRY, RPC_C_MEM_NOWAIT);
461
462    rpc__strncpy(ept_entry->annotation, annotation, ept_max_annotation_size - 1);
463
464    for (curr_hand = 0; curr_hand < binding_vec->count; curr_hand++)
465    {
466        rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_vec->binding_h[curr_hand];
467        /*
468         * Skip over NULL entries.
469         */
470
471        if (binding_rep == NULL)
472        {
473            continue;
474        }
475
476        if (binding_rep->rpc_addr && rpc_g_protseq_id[binding_rep->rpc_addr->rpc_protseq_id].uses_ep_mapper == 0)
477        {
478            /* Skip over protocol sequences that do not require the endpoint mapper */
479            continue;
480        }
481
482        /*
483         * Convert the binding handle to tower_ref vector.
484         */
485
486        rpc__tower_ref_vec_from_binding(if_rep, binding_vec->binding_h[curr_hand],
487                &tower_vec, status);
488        if (*status != rpc_s_ok)
489            break;
490
491        for (curr_tower = 0; curr_tower < tower_vec->count; curr_tower++)
492        {
493            rpc__tower_from_tower_ref(tower_vec->tower[curr_tower], &ept_entry->tower, status);
494            if (*status != rpc_s_ok)
495                break;
496
497            if (object_uuid_vec == NULL || object_uuid_vec->count == 0)
498            {
499                ept_entry->object = uuid_g_nil_uuid;
500                (*ept_v3_0_c_epv.ept_insert)
501                    (ep_binding, 1L, ept_entry, replace, status);
502                if (*status == rpc_s_call_cancelled)
503                    dcethread_interrupt_throw(dcethread_self());
504            }
505            else
506            {
507                for (curr_obj = 0; curr_obj < object_uuid_vec->count; curr_obj++)
508                {
509                    ept_entry->object = *object_uuid_vec->uuid[curr_obj];
510                    (*ept_v3_0_c_epv.ept_insert)
511                        (ep_binding, 1L, ept_entry, replace, status);
512                    if (*status == rpc_s_call_cancelled)
513                        dcethread_interrupt_throw(dcethread_self());
514                    if (*status != rpc_s_ok)
515                        break;
516                }
517            }
518
519            rpc__tower_free(&ept_entry->tower, &st);
520
521            if (*status != rpc_s_ok)
522                break;
523        }
524
525        rpc__tower_ref_vec_free(&tower_vec, &st);
526
527        if (*status != rpc_s_ok)
528            break;
529    }
530
531    rpc_binding_free(&ep_binding, &st);
532    RPC_MEM_FREE(ept_entry, RPC_C_MEM_EPT_ENTRY);
533
534    /*
535     * Handle any error conditions.  Try to unregister anything that was
536     * successfully registered.  Since we were trying to register the
537     * cross product of two vectors we need to separate recovery into
538     * 1) binding handles for which all objects were successfully registered
539     * and 2) binding handles for which some of the objects were successfully
540     * registered.
541     * Punt on the fact that multiple towers can be derived from each binding
542     * handle - all towers associated with a binding handle will be unregistered
543     * by rpc_ep_unregister.
544     */
545
546    if ((*status != rpc_s_ok) && (*status != rpc_s_comm_failure) &&
547        (curr_hand > 0 || curr_tower > 0 || curr_obj > 0))
548    {
549        rpc_binding_vector_p_t  bvp;
550        uuid_vector_p_t         ovp = NULL;
551        unsigned32              bv_size, ov_size;
552
553        /*
554         * First alloc a binding vector large enough to hold the number
555         * of handles for which all objects were successfully registered.
556         * (with a minimum size of 1 handle so that we can use it for the
557         * partially successful handle also).
558         */
559
560        bv_size = sizeof(rpc_binding_vector_t) + (sizeof(handle_t) * curr_hand);
561        RPC_MEM_ALLOC(bvp, rpc_binding_vector_p_t, bv_size,
562            RPC_C_MEM_BINDING_VEC, RPC_C_MEM_WAITOK);
563        if (bvp == NULL)
564        {
565            *status = rpc_s_no_memory;
566            return;
567        }
568
569        /*
570         * If there were any handles that were fully registered,
571         * unregister them now.
572         */
573
574        if (curr_hand > 0)
575        {
576            bvp->count = curr_hand;
577            for (j = 0; j < bvp->count; j++)
578                bvp->binding_h[j] = binding_vec->binding_h[j];
579
580            rpc_ep_unregister(ifspec, bvp, object_uuid_vec, &st);
581        }
582
583        /*
584         * If we got part way through registering the towers associated
585         * with a binding handle for an object, behave as if we registered
586         * all the towers associated with the binding handle and the object,
587         * ie. increment the curr_obj.
588         */
589        if (curr_tower > 0) curr_obj++;
590
591        /*
592         * If we got part way through registering the object vector for
593         * a particular handle, then we'll need to create a smaller copy
594         * of the object vector for unregistering only those objects that
595         * were actually registered (with that particular handle).
596         */
597
598        if (curr_obj > 0)
599        {
600            /*
601             * First create the partial object vector.
602             */
603
604            ov_size = sizeof(uuid_vector_t) + (sizeof(idl_uuid_t) * (curr_obj - 1));
605            RPC_MEM_ALLOC(ovp, uuid_vector_p_t, ov_size,
606                RPC_C_MEM_UUID_VECTOR, RPC_C_MEM_WAITOK);
607            if (ovp == NULL)
608            {
609                *status = rpc_s_no_memory;
610                RPC_MEM_FREE(bvp, RPC_C_MEM_UUID_VECTOR);
611                return;
612            }
613
614            ovp->count = curr_obj;
615            assert(object_uuid_vec != NULL);
616            for (j = 0; j < curr_obj; j++)
617                ovp->uuid[j] = object_uuid_vec->uuid[j];
618
619            /*
620             * Next, make a binding vector which contains only this
621             * particular handle.
622             */
623
624            bvp->count = 1;
625            bvp->binding_h[0] = binding_vec->binding_h[curr_hand];
626
627            rpc_ep_unregister(ifspec, bvp, ovp, &st);
628
629            RPC_MEM_FREE(ovp, RPC_C_MEM_UUID_VECTOR);
630        }
631
632        RPC_MEM_FREE(bvp, RPC_C_MEM_BINDING_VEC);
633    }
634}
635
636/*
637**++
638**
639**  ROUTINE NAME:       rpc_ep_unregister
640**
641**  SCOPE:              PUBLIC - declared in rpc.idl
642**
643**  DESCRIPTION:
644**
645**  Removes server address information from the endpoint mapper database.
646**  A server calls this routine only if the server has previously
647**  registered dynamically allocated endpoints.
648**
649**  INPUTS:
650**
651**      ifspec          Interface specification to unregister with the
652**                      endpoint mapper.
653**
654**      binding_vec     Vector of binding handles to unregister
655**
656**      object_uuid_vec A vector of object UUIDs to unregister
657**
658**  INPUTS/OUTPUTS:     none
659**
660**  OUTPUTS:
661**
662**      status          The result of the operation. One of:
663**                          rpc_s_ok
664**                          rpc_s_no_interfaces
665**                          rpc_s_no_bindings
666**                          rpc_s_invalid_binding
667**
668**  IMPLICIT INPUTS:    none
669**
670**  IMPLICIT OUTPUTS:   none
671**
672**  FUNCTION VALUE:     void
673**
674**  SIDE EFFECTS:       none
675**
676**--
677**/
678
679PUBLIC void rpc_ep_unregister
680(
681    rpc_if_handle_t             ifspec,
682    rpc_binding_vector_t        *binding_vec,
683    uuid_vector_t               *object_uuid_vec,
684    unsigned32                  *status
685)
686{
687    ept_entry_t                 *ept_entry;
688    rpc_if_rep_p_t              if_rep = (rpc_if_rep_p_t) ifspec;
689    rpc_binding_handle_t        ep_binding = NULL;
690    unsigned32                  i, j, k, st;
691    rpc_tower_ref_vector_p_t    tower_vec;
692    unsigned32                  curr_hand;
693    unsigned32                  lstatus;
694
695    CODING_ERROR (status);
696    RPC_VERIFY_INIT ();
697
698    if (ifspec == NULL)
699    {
700        *status = rpc_s_no_interfaces;
701        return;
702    }
703
704    if (binding_vec == NULL || binding_vec->count == 0)
705    {
706        *status = rpc_s_no_bindings;
707        return;
708    }
709
710#ifndef __hpux__
711    /*
712     * First attempt to contact the local endpoint mapper with ncalrpc.
713     * This should work even if the network has not yet come up
714     */
715    rpc_binding_from_string_binding(
716        (unsigned_char_t*) "ncalrpc:[epmapper]",
717        &ep_binding,
718        status);
719
720    if (*status == rpc_s_ok)
721    {
722        if (!rpc_mgmt_is_server_listening(ep_binding, status))
723        {
724            rpc_binding_free(&ep_binding, status);
725            ep_binding = NULL;
726        }
727    }
728#endif
729
730    if (!ep_binding)
731    {
732        /*
733         * Spin through the binding vector array looking for a non-NULL pointer
734         * to a binding handle.  If one is found set curr_hand to its offset in
735         * the binding vector.
736         * Also check for a binding handle with no endpoint; if one is found
737         * return an error.
738         */
739
740        curr_hand = binding_vec->count;
741        for (i = 0; i < binding_vec->count; i++)
742        {
743            if (binding_vec->binding_h[i] != NULL)
744            {
745                if (((rpc_binding_rep_p_t) binding_vec->binding_h[i])
746                    ->addr_has_endpoint == false)
747                {
748                    *status = rpc_s_invalid_binding;
749                    return;
750                }
751
752                curr_hand = i;
753            }
754        }
755
756        /*
757         * If all the handles were NULL'd out, return an error.
758         */
759
760        if (curr_hand >= binding_vec->count)
761        {
762            *status = rpc_s_no_bindings;
763            return;
764        }
765
766        /*
767         * Otherwise, use the a valid handle to converse with the EP mapper.
768         */
769
770        get_ep_binding(binding_vec->binding_h[curr_hand], &ep_binding, status);
771        if (*status != rpc_s_ok)
772            return;
773    }
774
775    /*
776     * Allocate the EP entry structure to avoid taking up stack space.
777     */
778
779    RPC_MEM_ALLOC(ept_entry, ept_entry_t *, sizeof *ept_entry,
780            RPC_C_MEM_EPT_ENTRY, RPC_C_MEM_NOWAIT);
781
782    ept_entry->annotation[0] = 0;
783
784    /*
785     * We will try to unregister the endpoints as much as possible and
786     * report the first error status we see (if that happens).
787     *
788     * Note: There is no particular reason why we report the first
789     * error. (It can be the last one or middle.) The better
790     * implementation is to make the endpoint mapper (rpcd) interface
791     * accept a vector of endpoints and return a vector of status codes
792     * for ept_insert() and ept_delete(). It may also improve the
793     * performance.
794     */
795
796    lstatus = rpc_s_ok;
797
798    for (i = 0; i < binding_vec->count; i++)
799    {
800        /*
801         * Skip over NULL entries.
802         */
803
804        if (binding_vec->binding_h[i] == NULL)
805            continue;
806
807        if (binding_vec->binding_h[i]->rpc_addr &&
808            rpc_g_protseq_id[binding_vec->binding_h[i]->rpc_addr->rpc_protseq_id].uses_ep_mapper == 0)
809        {
810            /* Skip over protocol sequences that do not require the endpoint mapper */
811            continue;
812        }
813
814        /*
815         * Convert the binding handle to tower_ref vector
816         */
817
818        rpc__tower_ref_vec_from_binding(if_rep, binding_vec->binding_h[i],
819                &tower_vec, &st);
820        if (st != rpc_s_ok)
821        {
822            if (lstatus == rpc_s_ok)
823                lstatus = st;
824
825            continue;
826        }
827
828        for (j = 0; j < tower_vec->count; j++)
829        {
830            rpc__tower_from_tower_ref(tower_vec->tower[j], &ept_entry->tower, &st);
831            if (st != rpc_s_ok)
832            {
833                if (lstatus == rpc_s_ok)
834                    lstatus = st;
835
836                continue;
837            }
838
839            if (object_uuid_vec == NULL || object_uuid_vec->count == 0)
840            {
841                ept_entry->object = uuid_g_nil_uuid;
842                (*ept_v3_0_c_epv.ept_delete)(ep_binding, 1L, ept_entry, &st);
843                if (st == rpc_s_call_cancelled)
844                    dcethread_interrupt_throw(dcethread_self());
845            }
846            else
847            {
848                for (k = 0; k < object_uuid_vec->count; k++)
849                {
850                    ept_entry->object = *object_uuid_vec->uuid[k];
851                    (*ept_v3_0_c_epv.ept_delete)(ep_binding, 1L, ept_entry, &st);
852                    if (st != rpc_s_ok)
853                    {
854                        if (*status == rpc_s_call_cancelled)
855                            dcethread_interrupt_throw(dcethread_self());
856                        if (lstatus == rpc_s_ok)
857                            lstatus = st;
858
859                        continue;
860                    }
861                }
862            }
863
864            if (st != rpc_s_ok)
865            {
866                if (lstatus == rpc_s_ok)
867                    lstatus = st;
868            }
869
870            rpc__tower_free(&ept_entry->tower, &st);
871        }
872
873        rpc__tower_ref_vec_free(&tower_vec, &st);
874    }
875
876    *status = lstatus;
877    rpc_binding_free(&ep_binding, &st);
878    RPC_MEM_FREE(ept_entry, RPC_C_MEM_EPT_ENTRY);
879}
880
881/*
882**++
883**
884**  ROUTINE NAME:       rpc_mgmt_ep_elt_inq_begin
885**
886**  SCOPE:              PUBLIC - declared in rpc.idl
887**
888**  DESCRIPTION:
889**
890**  Creates an inquiry context for viewing the elements in a local or
891**  remote endpoint map database.
892**
893**  INPUTS:
894**
895**      input_binding
896**
897**      inquiry_type
898**
899**      if_id
900**
901**      vers_option
902**
903**      object_uuid
904**
905**
906**  INPUTS/OUTPUTS:     none
907**
908**  OUTPUTS:
909**
910**      inquiry_context
911**
912**      status          The result of the operation.
913**
914**  IMPLICIT INPUTS:    none
915**
916**  IMPLICIT OUTPUTS:   none
917**
918**  FUNCTION VALUE:     void
919**
920**  SIDE EFFECTS:       none
921**
922**--
923**/
924
925PUBLIC void rpc_mgmt_ep_elt_inq_begin
926(
927    rpc_binding_handle_t    input_binding,
928    unsigned32              inquiry_type,
929    rpc_if_id_p_t           if_id,
930    unsigned32              vers_option,
931    uuid_p_t                object_uuid,
932    rpc_ep_inq_handle_t     *inquiry_context,
933    unsigned32              *status
934)
935{
936    mgmt_ep_inq_rep_t       *chp;
937    rpc_binding_handle_t    ep_binding;
938    idl_uuid_t                  UUID_NIL;
939    unsigned32              tmp_st;
940
941    CODING_ERROR (status);
942    RPC_VERIFY_INIT ();
943
944    if (inquiry_context == NULL)
945    {
946        *status = rpc_s_invalid_inquiry_context;
947        return;
948    }
949
950    *inquiry_context = NULL;
951
952    get_ep_binding(input_binding, &ep_binding, status);
953    if (*status != rpc_s_ok)
954        return;
955
956    RPC_MEM_ALLOC (
957        chp,
958        mgmt_ep_inq_rep_p_t,
959        sizeof (mgmt_ep_inq_rep_t),
960        RPC_C_MEM_INQ_REP,
961        RPC_C_MEM_WAITOK);
962
963    chp->usage = MGMT_EP_C_INQUIRY_CONTEXT;
964    chp->done = false;
965    chp->ep_binding = ep_binding;
966    chp->inquiry_type = inquiry_type;
967    chp->vers_option = vers_option;
968    chp->entry_handle = NULL;
969    chp->num_ents = 0;
970    chp->next_ent = 0;
971
972    /*
973     * Fill context's object and interface specs.  If object isn't being
974     * matched, use nil_uuid.  If interface isn't being matched, use
975     * nil_uuid and versions = 0.
976     */
977
978    uuid_create_nil(&UUID_NIL, &tmp_st);
979
980    switch ((int)inquiry_type)
981    {
982        case rpc_c_ep_all_elts:
983            chp->object = UUID_NIL;
984            chp->if_id.uuid = UUID_NIL;
985            chp->if_id.vers_major = 0;
986            chp->if_id.vers_minor = 0;
987            break;
988
989        case rpc_c_ep_match_by_if:
990            chp->object = UUID_NIL;
991            chp->if_id = *if_id;
992            break;
993
994        case rpc_c_ep_match_by_obj:
995            chp->object = *object_uuid;
996            chp->if_id.uuid = UUID_NIL;
997            chp->if_id.vers_major = 0;
998            chp->if_id.vers_minor = 0;
999            break;
1000
1001        case rpc_c_ep_match_by_both:
1002            chp->object = *object_uuid;
1003            chp->if_id = *if_id;
1004            break;
1005
1006        default:
1007            *status = rpc_s_invalid_inquiry_type;
1008            rpc_binding_free(&ep_binding, &tmp_st);
1009            RPC_MEM_FREE(chp, RPC_C_MEM_INQ_REP);
1010            return;
1011    }
1012
1013    if ((inquiry_type == rpc_c_ep_match_by_if) || (inquiry_type == rpc_c_ep_match_by_both))
1014    {
1015        switch((int)vers_option)
1016        {
1017            case rpc_c_vers_all:
1018            case rpc_c_vers_compatible:
1019            case rpc_c_vers_exact:
1020            case rpc_c_vers_major_only:
1021            case rpc_c_vers_upto:
1022                break;
1023
1024            default:
1025                *status = rpc_s_invalid_vers_option;
1026                rpc_binding_free(&ep_binding, &tmp_st);
1027                RPC_MEM_FREE(chp, RPC_C_MEM_INQ_REP);
1028                return;
1029        }
1030    }
1031
1032    *inquiry_context = (rpc_ep_inq_handle_t) chp;
1033
1034    *status = rpc_s_ok;
1035}
1036
1037
1038/*
1039**++
1040**
1041**  ROUTINE NAME:       rpc_mgmt_ep_elt_inq_next
1042**
1043**  SCOPE:              PUBLIC - declared in rpc.idl
1044**
1045**  DESCRIPTION:
1046**
1047**  Returns one element at a time from a local or remote endpoint map
1048**  database.
1049**
1050**  INPUTS:
1051**
1052**      inquiry_context
1053**
1054**  INPUTS/OUTPUTS:     none
1055**
1056**  OUTPUTS:
1057**
1058**      if_id
1059**
1060**      binding
1061**
1062**      object_uuid
1063**
1064**      annotation
1065**
1066**      status          The result of the operation.
1067**
1068**  IMPLICIT INPUTS:    none
1069**
1070**  IMPLICIT OUTPUTS:   none
1071**
1072**  FUNCTION VALUE:     void
1073**
1074**  SIDE EFFECTS:       none
1075**
1076**--
1077**/
1078PUBLIC void rpc_mgmt_ep_elt_inq_next
1079(
1080    rpc_ep_inq_handle_t       inquiry_context,
1081    rpc_if_id_t               *if_id,
1082    rpc_binding_handle_t      *binding,
1083    idl_uuid_t                    *object_uuid,
1084    unsigned_char_p_t         *annotation,
1085    unsigned32                *status
1086)
1087{
1088    mgmt_ep_inq_rep_t       *chp;
1089    ept_entry_t             *entp;
1090    unsigned32              asize;
1091    unsigned32              i;
1092    boolean32               supported_tower = false;
1093    rpc_ss_p_alloc_t        old_allocate;
1094    rpc_ss_p_alloc_t        tmp_allocate;
1095    rpc_ss_p_free_t         old_free;
1096    rpc_ss_p_free_t         tmp_free;
1097
1098    CODING_ERROR (status);
1099    RPC_VERIFY_INIT ();
1100
1101    if (inquiry_context == NULL)
1102    {
1103        *status = rpc_s_invalid_inquiry_context;
1104        return;
1105    }
1106
1107    chp = (mgmt_ep_inq_rep_t *) inquiry_context;
1108
1109    if (chp->usage != MGMT_EP_C_INQUIRY_CONTEXT)
1110    {
1111        *status = rpc_s_invalid_inquiry_context;
1112        return;
1113    }
1114
1115    if (if_id == NULL)
1116    {
1117        *status = rpc_s_invalid_arg;
1118        return;
1119    }
1120
1121    /*
1122     * Continue processing towers until we find one with a protseq
1123     * supported by this runtime.
1124     */
1125    while (!supported_tower)
1126    {
1127        /*
1128         * Check the done flag in the loop just in case the last
1129         * tower isn't supported. We don't want to go and start
1130         * reading towers from the beginning again.
1131         */
1132        if (chp->done)
1133        {
1134            *status = rpc_s_no_more_elements;
1135            return;
1136        }
1137
1138        if (chp->num_ents == 0)
1139        {
1140            /*
1141             * Force the stub to use a particular form of memory
1142             * allocation.
1143             */
1144            rpc_ss_swap_client_alloc_free (
1145                rpc__ep_mem_alloc, rpc__ep_mem_free,
1146                &old_allocate, &old_free);
1147
1148            /*
1149             *  No entries stashed away so read some from ept database
1150             */
1151            (*ept_v3_0_c_epv.ept_lookup)(chp->ep_binding,
1152                chp->inquiry_type, &chp->object, &chp->if_id, chp->vers_option,
1153                &chp->entry_handle, MAX_ENTS, &chp->num_ents, chp->entries,
1154                status);
1155
1156            /*
1157             * Restore the memory allocation scheme in effect before
1158             * we got here.
1159             */
1160            rpc_ss_swap_client_alloc_free (
1161                old_allocate, old_free,
1162                &tmp_allocate, &tmp_free);
1163
1164            if (*status != rpc_s_ok)
1165            {
1166                if (*status == ept_s_not_registered)
1167                    *status = rpc_s_no_more_elements;
1168                if (*status == rpc_s_call_cancelled)
1169                    dcethread_interrupt_throw(dcethread_self());
1170                return;
1171            }
1172            chp->next_ent = 0;
1173        }
1174
1175        entp = &(chp->entries[chp->next_ent]);
1176
1177        if (binding != NULL)
1178        {
1179            rpc_tower_to_binding(entp->tower->tower_octet_string, binding,
1180                                    status);
1181
1182            /*
1183             * If the conversion was ok, we have a supported tower.
1184             * If the tower is of an unsupported protseq, we filter it out.
1185             * Any other status is a problem, so return.
1186             */
1187            if (*status == rpc_s_ok)
1188            {
1189                supported_tower = true;
1190            }
1191            else
1192            {
1193                if (*status != rpc_s_protseq_not_supported)
1194                {
1195                    return;
1196                }
1197            }
1198        }
1199
1200        /*
1201         * The caller doesn't want the binding, so consider the tower supported
1202         * to return the other fields.
1203         */
1204        else
1205        {
1206            supported_tower = true;
1207        }
1208
1209        if (supported_tower)
1210        {
1211            tower_to_if_id(entp->tower, if_id, status);
1212            if (*status != rpc_s_ok)
1213                return;
1214
1215            if (object_uuid != NULL)
1216                *object_uuid = entp->object;
1217
1218            if (annotation != NULL)
1219            {
1220                asize = (unsigned32)strlen((char *) entp->annotation) + 1;
1221
1222                RPC_MEM_ALLOC (
1223                    *annotation,
1224                    unsigned_char_p_t,
1225                    asize,
1226                    RPC_C_MEM_STRING,
1227                    RPC_C_MEM_WAITOK);
1228
1229                rpc__strncpy(*annotation, entp->annotation, (asize-1));
1230             }
1231        }
1232
1233        chp->next_ent++;
1234
1235        if (chp->next_ent >= chp->num_ents)
1236        {
1237            /*
1238             *  Have returned all entries that are stashed away for this
1239             *  context to the caller.
1240             *  Free the towers.
1241             */
1242            for (i = 0, entp = &(chp->entries[0]);
1243                i < chp->num_ents;
1244                i++, entp++)
1245            {
1246                rpc__ep_mem_free (NULL, (dce_pointer_t) entp->tower);
1247            }
1248
1249            chp->num_ents = 0;
1250            chp->next_ent = 0;
1251
1252            /*
1253             * If entry handle is NULL, all matching entries have been read
1254             * so mark context as done.
1255             */
1256            if (chp->entry_handle == NULL)
1257                chp->done = true;
1258        }
1259    }
1260
1261    *status = rpc_s_ok;
1262}
1263
1264/*
1265**++
1266**
1267**  ROUTINE NAME:       rpc_mgmt_ep_elt_inq_done
1268**
1269**  SCOPE:              PUBLIC - declared in rpc.idl
1270**
1271**  DESCRIPTION:
1272**
1273**  Deletes the inquiry context for viewing the elements in a local or
1274**  remote endpoint map database.
1275**
1276**  INPUTS:             none
1277**
1278**  INPUTS/OUTPUTS:
1279**
1280**      inquiry_context
1281**
1282**  OUTPUTS:
1283**
1284**      status          The result of the operation.
1285**
1286**  IMPLICIT INPUTS:    none
1287**
1288**  IMPLICIT OUTPUTS:   none
1289**
1290**  FUNCTION VALUE:     void
1291**
1292**  SIDE EFFECTS:       none
1293**
1294**--
1295**/
1296
1297PUBLIC void rpc_mgmt_ep_elt_inq_done
1298(
1299    rpc_ep_inq_handle_t     *inquiry_context,
1300    unsigned32              *status
1301)
1302{
1303    mgmt_ep_inq_rep_t       *chp;
1304    ept_entry_t             *entp;
1305    unsigned32              i;
1306
1307    CODING_ERROR (status);
1308    RPC_VERIFY_INIT ();
1309
1310    if ((inquiry_context == NULL) || (*inquiry_context == NULL))
1311    {
1312        *status = rpc_s_invalid_inquiry_context;
1313        return;
1314    }
1315
1316    chp = (mgmt_ep_inq_rep_t *) (*inquiry_context);
1317
1318    if (chp->usage != MGMT_EP_C_INQUIRY_CONTEXT)
1319    {
1320        *status = rpc_s_invalid_inquiry_context;
1321        return;
1322    }
1323
1324    if (chp->entry_handle != NULL)
1325        (*ept_v3_0_c_epv.ept_lookup_handle_free)(chp->ep_binding, &chp->entry_handle, status);
1326    if (*status == rpc_s_call_cancelled)
1327        dcethread_interrupt_throw(dcethread_self());
1328
1329    rpc_binding_free(&chp->ep_binding, status);
1330
1331    for (i = 0, entp = &(chp->entries[0]); i < chp->num_ents; i++, entp++)
1332        rpc__ep_mem_free (NULL, (dce_pointer_t) entp->tower);
1333
1334    RPC_MEM_FREE(chp, RPC_C_MEM_INQ_REP);
1335
1336    *inquiry_context = NULL;
1337
1338    *status = rpc_s_ok;
1339}
1340
1341/*
1342**++
1343**
1344**  ROUTINE NAME:       rpc_mgmt_ep_unregister
1345**
1346**  SCOPE:              PUBLIC - declared in rpc.idl
1347**
1348**  DESCRIPTION:
1349**
1350**  Removes server address information from an endpoint map database.
1351**
1352**  INPUTS:             none
1353**
1354**  INPUTS/OUTPUTS:
1355**
1356**      input_binding
1357**
1358**      if_id
1359**
1360**      object_uuid
1361**
1362**  OUTPUTS:
1363**
1364**      status          The result of the operation.
1365**
1366**  IMPLICIT INPUTS:    none
1367**
1368**  IMPLICIT OUTPUTS:   none
1369**
1370**  FUNCTION VALUE:     void
1371**
1372**  SIDE EFFECTS:       none
1373**
1374**--
1375**/
1376
1377PUBLIC void rpc_mgmt_ep_unregister
1378(
1379    rpc_binding_handle_t    input_binding,
1380    rpc_if_id_p_t           if_id,
1381    rpc_binding_handle_t    binding,
1382    uuid_p_t                object_uuid,
1383    unsigned32              *status
1384)
1385{
1386    rpc_binding_handle_t        ep_binding;
1387    rpc_tower_ref_vector_p_t    tower_vec;
1388    twr_p_t                     tower;
1389    boolean32                   object_speced;
1390    idl_uuid_t                      UUID_NIL;
1391    idl_uuid_t                      *objp;
1392    error_status_t              tmp_st;
1393    rpc_if_rep_t                ifspec;
1394
1395    static rpc_syntax_id_t ndr_syntax_id = {
1396        {0x8a885d04UL, 0x1ceb, 0x11c9, 0x9f, 0xe8, {0x8, 0x0, 0x2b, 0x10, 0x48, 0x60}},
1397        2
1398    };
1399    static rpc_if_rep_t ifspec_template = {
1400      1, /* ifspec rep version */
1401      4, /* op count */
1402      4, /* if version */
1403      {0, 0, 0, 0, 0, {0}}, /* uuid */
1404      2, /* stub/rt if version */
1405      {0, NULL}, /* endpoint vector */
1406      {1, &ndr_syntax_id}, /* syntax vector */
1407      NULL, /* server_epv */
1408      NULL /* manager epv */
1409    };
1410
1411    if (if_id == NULL)
1412    {
1413        *status = rpc_s_no_interfaces;
1414        return;
1415    }
1416
1417    if (binding == NULL)
1418    {
1419        *status = rpc_s_invalid_binding;
1420        return;
1421    }
1422
1423    /*
1424     * Get handle to local or remote endpoint mapper
1425     */
1426    get_ep_binding(input_binding, &ep_binding, status);
1427    if (*status != rpc_s_ok)
1428        return;
1429
1430    /*
1431     * Make up an ifspec from the template
1432     */
1433    ifspec = ifspec_template;
1434    ifspec.id = if_id->uuid;
1435    ifspec.vers = if_id->vers_minor << 16 | if_id->vers_major;
1436
1437    /*
1438     * Convert the binding handle to tower_ref vector and then to a tower
1439     */
1440
1441    rpc__tower_ref_vec_from_binding(&ifspec, binding, &tower_vec, status);
1442    if (*status != rpc_s_ok)
1443    {
1444        rpc_binding_free(&ep_binding, &tmp_st);
1445        return;
1446    }
1447
1448    rpc__tower_from_tower_ref(tower_vec->tower[0], &tower, status);
1449    if (*status != rpc_s_ok)
1450    {
1451        rpc_binding_free(&ep_binding, &tmp_st);
1452        rpc__tower_ref_vec_free(&tower_vec, &tmp_st);
1453        return;
1454    }
1455
1456    if (object_uuid == NULL)
1457    {
1458        object_speced = false;
1459        uuid_create_nil(&UUID_NIL, &tmp_st);
1460        objp = &UUID_NIL;
1461    }
1462    else
1463    {
1464        object_speced = true;
1465        objp = object_uuid;
1466    }
1467
1468    (*ept_v3_0_c_epv.ept_mgmt_delete)
1469        (ep_binding, object_speced, objp, tower, status);
1470
1471    if (*status == rpc_s_call_cancelled)
1472        dcethread_interrupt_throw(dcethread_self());
1473
1474    rpc__tower_free(&tower, &tmp_st);
1475    rpc__tower_ref_vec_free(&tower_vec, &tmp_st);
1476    rpc_binding_free(&ep_binding, &tmp_st);
1477}
1478
1479
1480/*
1481**++
1482**
1483**  ROUTINE NAME:       get_ep_binding
1484**
1485**  SCOPE:              INTERNAL
1486**
1487**  DESCRIPTION:
1488**
1489**  Return a binding to an endpoint mapper.
1490**
1491**  INPUTS:
1492**
1493**      input_binding   Binding from which we should derive a binding on the
1494**                      endpoint mapper.  Can be NULL to mean the endpoint
1495**                      mapper on the local host.
1496**
1497**  INPUTS/OUTPUTS:     none
1498**
1499**  OUTPUTS:
1500**
1501**      output_binding  Binding on the endpoint mapper.
1502**
1503**      status          The result of the operation.
1504**
1505**  IMPLICIT INPUTS:    none
1506**
1507**  IMPLICIT OUTPUTS:   none
1508**
1509**  FUNCTION VALUE:     void
1510**
1511**  SIDE EFFECTS:       none
1512**
1513**--
1514**/
1515
1516INTERNAL void get_ep_binding
1517(
1518    rpc_binding_handle_t    input_binding,
1519    rpc_binding_handle_t    *output_binding,
1520    unsigned32              *status
1521)
1522{
1523    rpc_protseq_vector_t    *protseq_vector;
1524    unsigned_char_t         protseq_str[64];
1525    size_t                  slen;
1526    unsigned32              i;
1527    unsigned32              tmp_st;
1528
1529    /* Workaround due to not having Named Pipe client support yet. */
1530    if (input_binding != NULL &&
1531        input_binding->rpc_addr != NULL &&
1532        input_binding->rpc_addr->rpc_protseq_id == rpc_c_protseq_id_ncacn_np)
1533    {
1534        input_binding = NULL;
1535    }
1536
1537    if (input_binding == NULL)
1538    {
1539        /*
1540         * No binding specified.  Try to bind to the local rpcd using
1541         * one of the host's supported protseqs.
1542         */
1543        rpc_network_inq_protseqs(&protseq_vector, status);
1544        if (*status != rpc_s_ok)
1545            return;
1546
1547        for (i = 0; i < protseq_vector->count; i++)
1548        {
1549            slen = strlen((char *) protseq_vector->protseq[i]);
1550            if ((slen + 2) > sizeof(protseq_str))
1551                continue;
1552
1553            rpc__strncpy(protseq_str, protseq_vector->protseq[i], slen);
1554            rpc__strncpy(&protseq_str[slen], (unsigned_char_t *) ":", 1);
1555
1556            rpc_binding_from_string_binding(protseq_str, output_binding, status);
1557            if (*status == rpc_s_ok)
1558                break;
1559        }
1560
1561        if (i >= protseq_vector->count)
1562        {
1563            /*
1564             * Unable to get a binding to one of the protseqs
1565             */
1566            *status = rpc_s_no_protseqs;
1567        }
1568
1569        rpc_protseq_vector_free(&protseq_vector, status);
1570    }
1571    else
1572    {
1573        /*
1574         * A binding was specified.  Make sure it's the right kind.  Copy it,
1575         * and reset the copy's endpoint, com timeout setting, and auth info
1576         */
1577
1578        RPC_BINDING_VALIDATE_CLIENT((rpc_binding_rep_p_t) input_binding, status);
1579
1580        rpc_binding_copy(input_binding, output_binding, status);
1581        if (*status != rpc_s_ok)
1582            return;
1583
1584        rpc_binding_reset(*output_binding, status);
1585        if (*status != rpc_s_ok)
1586        {
1587            rpc_binding_free(output_binding, &tmp_st);
1588            return;
1589        }
1590
1591        rpc_mgmt_set_com_timeout (*output_binding, rpc_c_binding_default_timeout, status);
1592        if (*status != rpc_s_ok)
1593        {
1594            rpc_binding_free(output_binding, &tmp_st);
1595            return;
1596        }
1597
1598        rpc_binding_set_auth_info (*output_binding, NULL, rpc_c_authn_level_default,
1599                                    rpc_c_authn_none, NULL, rpc_c_authz_none, status);
1600        if (*status != rpc_s_ok)
1601        {
1602            rpc_binding_free(output_binding, &tmp_st);
1603            return;
1604        }
1605
1606    }
1607}
1608
1609/*
1610**++
1611**
1612**  ROUTINE NAME:       rpc_binding_to_epmap
1613**
1614**  SCOPE:              PRIVATE
1615**
1616**  DESCRIPTION:
1617**
1618**  Return a binding to an endpoint mapper.
1619**
1620**  INPUTS:
1621**
1622**      input_binding   Binding from which we should derive a binding on the
1623**                      endpoint mapper.  Can be NULL to mean the endpoint
1624**                      mapper on the local host.
1625**
1626**  INPUTS/OUTPUTS:     none
1627**
1628**  OUTPUTS:
1629**
1630**      output_binding  Binding on the endpoint mapper.
1631**
1632**      status          The result of the operation.
1633**
1634**  IMPLICIT INPUTS:    none
1635**
1636**  IMPLICIT OUTPUTS:   none
1637**
1638**  FUNCTION VALUE:     void
1639**
1640**  SIDE EFFECTS:       none
1641**
1642**--
1643**/
1644PRIVATE void rpc_binding_to_epmap
1645(
1646    rpc_binding_handle_t    input_binding,
1647    rpc_binding_handle_t    *output_binding,
1648    unsigned32              *status
1649)
1650{
1651    get_ep_binding(input_binding, output_binding, status);
1652}
1653
1654/*
1655**++
1656**
1657**  ROUTINE NAME:       tower_to_if
1658**
1659**  SCOPE:              INTERNAL
1660**
1661**  DESCRIPTION:
1662**
1663**  Convert a tower to an interface ID.
1664**
1665**  INPUTS:
1666**
1667**      tower
1668**
1669**  INPUTS/OUTPUTS:     none
1670**
1671**  OUTPUTS:
1672**
1673**      if_id
1674**
1675**      status          The result of the operation.
1676**
1677**  IMPLICIT INPUTS:    none
1678**
1679**  IMPLICIT OUTPUTS:   none
1680**
1681**  FUNCTION VALUE:     void
1682**
1683**  SIDE EFFECTS:       none
1684**
1685**--
1686**/
1687
1688INTERNAL void tower_to_if_id
1689(
1690    twr_p_t         tower,
1691    rpc_if_id_t     *if_id,
1692    unsigned32      *status
1693)
1694{
1695    rpc_tower_ref_t *tref;
1696    unsigned32      tmp_st;
1697
1698    rpc__tower_to_tower_ref(tower, &tref, status);
1699    if (*status != rpc_s_ok)
1700        return;
1701
1702    if (tref->count < RPC_C_NUM_RPC_FLOORS)
1703    {
1704        *status = ept_s_invalid_entry;
1705        return;
1706    }
1707
1708    rpc__tower_flr_to_if_id(tref->floor[0], if_id, status);
1709
1710    rpc__tower_ref_free(&tref, &tmp_st);
1711}
1712
1713/*
1714**++
1715**
1716**  ROUTINE NAME:       rpc_ep_resolve_binding
1717**
1718**  SCOPE:              PUBLIC - declared in rpc.idl
1719**
1720**  DESCRIPTION:
1721**
1722**        An application calls the rpc_ep_resolve_binding
1723**        routine to resolve a partially-bound server binding
1724**        handle into a fully-bound binding handle.
1725**
1726**        Resolving binding handles requires an interface UUID
1727**        and an object UUID (which may be nil). The RPC runtime
1728**        requests the RPC daemon (rpcd) on the host specified
1729**        by the binding argument to look up an endpoint for
1730**        a compatible server instance. To find the endpoint,
1731**        the rpcd looks in the endpoint map for the interface
1732**        UUID from the if_spec argument and the object UUID
1733**        in the binding argument, if any. (For a discussion
1734**        on how rpcd locates compatible server instances, see
1735**        Chapter 11 in the Functional Spec.)
1736**
1737**        The functioning of the resolve-binding operation
1738**        depends on whether the specified binding handle is
1739**        partially or fully bound. When the client specifies a
1740**        partially-bound handle, the resolve-binding operation
1741**        has the following possible outcomes:
1742**
1743**        o  If no compatible server instances are registered
1744**           in the endpoint map, the resolve-binding operation
1745**           returns the ept_s_not_registered status code.
1746**
1747**        o  If a compatible server instance is registered in
1748**           the endpoint map, the resolve-binding operation
1749**           returns a fully-bound binding and the rpc_s_ok
1750**           status code.
1751**
1752**        When the client specifies a fully-bound binding
1753**        handle, the resolve-binding operation returns the
1754**        specified binding handle and the rpc_s_ok status code.
1755**        The resolve-binding operation does not contact the
1756**        rpcd.
1757**
1758**        In neither the partially- or fully-bound binding
1759**        case, does the resolve-binding operation contact a
1760**        compatible server instance.
1761**
1762**
1763**  INPUTS:
1764**
1765**        if_spec       A stub generated data structure specifying the
1766**                      interface of interest.
1767**
1768**  INPUTS/OUTPUTS:     none
1769**
1770**        binding       A partially bound server binding handle to resolve to
1771**                      a fully bound server binding handle.
1772**
1773**  OUTPUTS:
1774**
1775**        status        Returns the status code from the resolve binding
1776**                      operation. This status code is a value that indicates
1777**                      whether the routine completed successfully and, if
1778**                      not, why.
1779**                      rpc_s_ok                        The call completed normally.
1780**                      ept_s_not_registered            No entries found
1781**                      rpc_s_invalid_binding           Invalid binding handle
1782**                      rpc_s_wrong_kind_of_binding     Wrong kind of binding for
1783**                                                      operation
1784**                      rpc_s_rpcd_comm_failure         rpc daemon
1785**                                                      communications failure
1786**  IMPLICIT INPUTS:    none
1787**
1788**  IMPLICIT OUTPUTS:   none
1789**
1790**  FUNCTION VALUE:     none
1791**
1792**  SIDE EFFECTS:
1793**
1794**      This routine does not check for concurrent use of the
1795**      binding handle. It is up to the user of this routine to
1796**      ensure the consistency and correctness of the binding handle
1797**      by restricting concurrent use of it across multiple threads.
1798**      This is the same guarantee the user must provide while modifying
1799**      other binding fields, such as the object UUID, endpoint, and
1800**      auth info.
1801**
1802**--
1803**/
1804
1805PUBLIC void rpc_ep_resolve_binding
1806(
1807    rpc_binding_handle_t  binding_h,
1808    rpc_if_handle_t       if_spec_h,
1809    unsigned32            *status
1810)
1811{
1812    rpc_binding_rep_p_t     binding_rep = (rpc_binding_rep_p_t) binding_h;
1813
1814    assert(binding_rep != NULL);
1815
1816    CODING_ERROR (status);
1817    RPC_VERIFY_INIT ();
1818    RPC_BINDING_VALIDATE_CLIENT (binding_rep, status);
1819    if (*status != rpc_s_ok)
1820    {
1821        return;
1822    }
1823
1824    /*
1825     * Determine whther the specified binding handle is
1826     * partially or fully bound.
1827     */
1828    if (!binding_rep->addr_has_endpoint)
1829    {
1830        /*
1831         * The binding is partially bound. Prevent other threads
1832         * from using this handle while we are trying to resolve
1833         * it.
1834         */
1835        ep_get_endpoint ((rpc_if_rep_p_t) if_spec_h, binding_rep, status);
1836    }
1837    else
1838    {
1839        /*
1840         * The binding is fully bound. Just return it.
1841         */
1842        *status = rpc_s_ok;
1843    }
1844}
1845
1846
1847/*
1848**++
1849**
1850**  ROUTINE NAME:       ep_get_endpoint
1851**
1852**  SCOPE:              INTERNAL - declared locally
1853**
1854**  DESCRIPTION:
1855**
1856**      Find the correct endpoint information and plug it into the
1857**      binding rep. This routine is called by rpc_ep_resolve_binding
1858**      when the binding is not fully bound.
1859**
1860**      We first check the i/f spec to see if the endpoint information
1861**      is there to use. If not, we make an RPC call to the endpoint
1862**      mapper on the node specified in the binding handle to obtain
1863**      the endpoint information for the specified interface. Then we
1864**      plug in the endpoint (returned from ep_map()) in the binding
1865**      handle.
1866**
1867**
1868**  INPUTS:
1869**
1870**      if_r            a pointer to the interface spec of interest
1871**
1872**  INPUTS/OUTPUTS:
1873**
1874**      binding_r       a pointer to the binding rep which requires an endpoint
1875**
1876**  OUTPUTS:            none
1877**
1878**      st              The return status of this routine.
1879**                      rpc_s_ok          The call completed normally.
1880**                      rpc_s_rpcd_comm_failure         rpc daemon
1881**                                                      communications failure
1882**  IMPLICIT INPUTS:    none
1883**
1884**  IMPLICIT OUTPUTS:   none
1885**
1886**  FUNCTION VALUE:     none
1887**
1888**  SIDE EFFECTS:       none
1889**
1890**--
1891**/
1892
1893INTERNAL void ep_get_endpoint
1894(
1895    rpc_if_rep_p_t          if_r,
1896    rpc_binding_rep_p_t     binding_r,
1897    unsigned32              *st
1898)
1899{
1900    unsigned32                  temp_status;
1901    unsigned_char_p_t           endpoint = NULL;
1902    ept_lookup_handle_t         map_lookup_handle;
1903    rpc_addr_p_t                *rpc_addr;
1904    unsigned32                  saved_timeout;
1905    idl_uuid_t                      saved_object_uuid;
1906    rpc_tower_ref_vector_p_t    tower_vector = NULL;
1907    twr_p_t                     map_tower = NULL;
1908    twr_p_t                     * volatile towers = NULL;
1909    unsigned32                  num_towers = 0;
1910    rpc_addr_p_t                tower_rpc_addr = NULL;
1911    rpc_auth_info_t             *saved_auth_info;
1912    unsigned32                  tower_to_use;
1913    unsigned32                  i, j;
1914    volatile boolean32                   full_restore_flag = true;
1915    boolean32                   map_lookup;
1916    volatile boolean32                   free_prot_version = false;
1917    rpc_ss_p_alloc_t            old_allocate;
1918    rpc_ss_p_alloc_t            tmp_allocate;
1919    rpc_ss_p_free_t             old_free;
1920    rpc_ss_p_free_t             tmp_free;
1921
1922//	DO_NOT_CLOBBER(towers);
1923	towers = NULL;
1924//	DO_NOT_CLOBBER(full_restore_flag);
1925	full_restore_flag = true;
1926//	DO_NOT_CLOBBER(free_prot_version);
1927	free_prot_version = true;
1928
1929    CODING_ERROR (st);
1930
1931    rpc_addr = &binding_r->rpc_addr;
1932
1933    /*
1934     * Get the endpoint from the i/f spec, if present.
1935     */
1936    rpc__if_set_wk_endpoint (if_r, rpc_addr, st);
1937    if (*st == rpc_s_ok)
1938    {
1939        /*
1940         * Notify the protocol service that the binding has changed.
1941         */
1942        (*rpc_g_protocol_id[binding_r->protocol_id].binding_epv
1943             ->binding_changed) (binding_r, st);
1944
1945        if (*st != rpc_s_ok)
1946        {
1947            return;
1948        }
1949
1950        /*
1951         * The binding now contains the endpoint in the
1952         * interface spec.
1953         */
1954        binding_r->addr_has_endpoint = true;
1955
1956        return;
1957    }
1958
1959    if (*st != rpc_s_endpoint_not_found)
1960    {
1961        return;
1962    }
1963    else
1964    {
1965        /*
1966         * Save away the binding object UUID before
1967         * making the endpoint map call. The endpoint map
1968         * call must be made with a binding which either
1969         * has a nil object UUID or the well-known object
1970         * UUID for this instantiation of the endpoint
1971         * database.
1972         */
1973        rpc_binding_inq_object ((rpc_binding_handle_t) binding_r,
1974                                &saved_object_uuid,
1975                                st);
1976
1977        if (*st != rpc_s_ok)
1978        {
1979            return;
1980        }
1981
1982        /*
1983         * Save away the com timeout in the binding just in case
1984         * it's set to infinite. We really don't want to try
1985         * forever to reach the endpoint mapper.
1986         */
1987        rpc_mgmt_inq_com_timeout ((rpc_binding_handle_t) binding_r,
1988                                  &saved_timeout, st);
1989
1990        if (*st != rpc_s_ok)
1991        {
1992            return;
1993        }
1994
1995        /*
1996         * Save the auth info on the binding.
1997         * The call to the endpoint mapper will
1998         * not be authenticated.
1999         */
2000        saved_auth_info = binding_r->auth_info;
2001
2002        /*
2003         * Set the binding object to nil.
2004         */
2005        rpc_binding_set_object ((rpc_binding_handle_t) binding_r,
2006                                &uuid_g_nil_uuid,
2007                                st);
2008
2009        if (*st != rpc_s_ok)
2010        {
2011            goto CLEANUP;
2012        }
2013
2014        rpc_mgmt_set_com_timeout ((rpc_binding_handle_t) binding_r,
2015                                  rpc_c_binding_default_timeout, st);
2016
2017        if (*st != rpc_s_ok)
2018        {
2019            goto CLEANUP;
2020        }
2021
2022        binding_r->auth_info = NULL;
2023
2024        /*
2025         * Construct a (fully-bound) handle to the Endpoint
2026         * Mapper at the target node.
2027         * We do this by taking the partially bound handle
2028         * and setting the endpoint to the well-known
2029         * endpoint associated with the EP interface
2030         * (for the designated protocol sequence).
2031         */
2032        rpc__if_set_wk_endpoint ((rpc_if_rep_p_t) ept_v3_0_c_ifspec,
2033                                 rpc_addr,
2034                                 st);
2035        if (*st != rpc_s_ok)
2036        {
2037            goto CLEANUP;
2038        }
2039        /*
2040         * If this binding handle doesn't have a protocol version
2041         * attached to it (probably a string binding), then
2042         * create one that will insure we will get an endpoint.
2043         */
2044        if (binding_r->protocol_version == NULL)
2045        {
2046           unsigned8          temp_prot_id;
2047           unsigned32         temp_vers_major,
2048                              temp_vers_minor;
2049
2050           rpc__network_inq_prot_version(binding_r->rpc_addr->rpc_protseq_id,
2051                                         &temp_prot_id,
2052                                         &temp_vers_major,
2053                                         &temp_vers_minor,
2054                                         st);
2055
2056           if (*st != rpc_s_ok)
2057           {
2058               goto CLEANUP;
2059           }
2060
2061           /*
2062            * This is ugly, but if we are talking to a 1.0.x rpcd,
2063            * it wont give us an endpoint if our minor number is
2064            * higher than the servers.
2065            */
2066           rpc__binding_prot_version_alloc(&(binding_r->protocol_version),
2067                                           temp_vers_major,
2068                                           0,
2069                                           st);
2070           if (*st != rpc_s_ok)
2071           {
2072               goto CLEANUP;
2073           }
2074
2075           /* remember to free this when we get the endpoint */
2076           free_prot_version = true;
2077        }
2078
2079        /*
2080         * Notify the protocol service that the binding
2081         * has changed.
2082         */
2083        (*rpc_g_protocol_id[binding_r->protocol_id].binding_epv
2084         ->binding_changed) (binding_r, st);
2085
2086        if (*st != rpc_s_ok)
2087        {
2088            goto CLEANUP;
2089        }
2090
2091        binding_r->addr_has_endpoint = true;
2092
2093        /*
2094         * In order to lookup entries in the endpoint mapper
2095         * database we need to provide a map tower which it will
2096         * use as a lookup key. The important fields in the tower
2097         * are the interface UUID and version, data rep, protocol
2098         * sequence and RPC protocol version. To create the map
2099         * tower the binding given by the client, which contains
2100         * the correct protocol sequence and the interface spec,
2101         * which contains the interface UUID and version and data
2102         * rep(s). This information will be converted into a
2103         * vector of tower ref structures (one for each data rep).
2104         * These tower ref structures can then be converted into a
2105         * real tower, the map tower. The output of the endpoint
2106         * map will also be a tower containing the desired
2107         * endpoint. This tower will be converted into an RPC
2108         * address, from which the endpoint will be extracted.
2109         * Finally the endpoint will be set in the original
2110         * binding.
2111         *
2112         * NOTE: When logic to iterate through the endpoint
2113         * mapper database if the presentation negotiation fails
2114         * is added an iteration will have to be done for each
2115         * tower ref gotten from the binding,ifspec tuple. For
2116         * right now only the first tower ref in the vector is
2117         * looked at and no iteration is done with it.
2118         */
2119        rpc__tower_ref_vec_from_binding (if_r,
2120                                         (rpc_binding_handle_t )binding_r,
2121                                         &tower_vector, st);
2122
2123        if (*st != rpc_s_ok)
2124        {
2125            goto CLEANUP;
2126        }
2127
2128        rpc__tower_from_tower_ref (tower_vector->tower[0],
2129                                   &map_tower, st);
2130
2131        if (*st != rpc_s_ok)
2132        {
2133            goto CLEANUP;
2134        }
2135
2136        /*
2137         * We want to get *all* of the compatible towers back from
2138         * the ep map so that we can randomly select one to provide
2139         * an endpoint to the caller's binding handle.
2140         * We get all to the towers by allocating memory to hold
2141         * MAX_TOWERS compatible towers. If it turns out that
2142         * MAX_TOWERS is not sufficient, then we free the towers
2143         * and try again allowing for MAX_TOWERS x 2 towers.
2144         * This continues ( x 3; x 4; ...) until we get them all
2145         * in one call.
2146         */
2147        DCETHREAD_TRY
2148        {
2149        /*
2150         * The increment i specifies the multiples of MAX_TOWERS
2151         * towers to get.
2152         *
2153         * The map lookup boolean signifies whether we have to try
2154         * again with a larger towers size.
2155         *
2156         * The map lookup handle, which is really a context handle, must be
2157         * initialized to NULL unless we are iterating.
2158         */
2159            for (i = 1, map_lookup = true, map_lookup_handle = NULL;
2160                 map_lookup == true;
2161                 ++i)
2162            {
2163                RPC_MEM_ALLOC (
2164                               towers,
2165                               twr_p_t *,
2166                               sizeof(twr_p_t) * (MAX_TOWERS * i),
2167                               RPC_C_MEM_TOWER,
2168                               RPC_C_MEM_NOWAIT);
2169                /*
2170                 * Set all the pointers in the array to NULL.
2171                 */
2172                memset (towers, 0, sizeof(twr_p_t) * (MAX_TOWERS * i));
2173
2174                /*
2175                 * Force the stub to use a particular form of memory
2176                 * allocation.
2177                 */
2178               rpc_ss_swap_client_alloc_free (
2179                   rpc__ep_mem_alloc, rpc__ep_mem_free,
2180                   &old_allocate, &old_free);
2181
2182                (*ept_v3_0_c_epv.ept_map)
2183                ((rpc_binding_handle_t) binding_r,
2184                 &saved_object_uuid,
2185                 map_tower,
2186                 &map_lookup_handle,
2187                 MAX_TOWERS * i,
2188                 &num_towers,
2189                 towers,
2190                 st);
2191
2192                /*
2193                 * Restore the memory allocation scheme in effect before
2194                 * we got here
2195                 */
2196                rpc_ss_swap_client_alloc_free (
2197                    old_allocate, old_free,
2198                    &tmp_allocate, &tmp_free);
2199
2200                /*
2201                 * If we got all  of the compatible bindings, we're
2202                 * done with ep map.
2203                 * Otherwise, let's get rid of the ones returned (this was
2204                 * memory allocated by the stub) and we'll try again.
2205                 */
2206                if (map_lookup_handle == NULL)
2207                {
2208                    map_lookup = false;
2209                }
2210                else
2211                {
2212                    for (j = 0; j < num_towers; ++j)
2213                    {
2214                        rpc__ep_mem_free (NULL, (dce_pointer_t) towers[j]);
2215                    }
2216
2217                    RPC_MEM_FREE (towers, RPC_C_MEM_TOWER);
2218
2219                    /*
2220                     * So we'll know what to do for cleanup.
2221                     */
2222                    towers = NULL;
2223
2224                    /*
2225                     * Free the lookup handle at rpcd.
2226                     */
2227                    (*ept_v3_0_c_epv.ept_lookup_handle_free)
2228                    ((rpc_binding_handle_t) binding_r,
2229                     &map_lookup_handle,
2230                     &temp_status);
2231
2232                    if (temp_status == rpc_s_call_cancelled)
2233                        dcethread_interrupt_throw(dcethread_self());
2234
2235                    /*
2236                     * We'll ignore any problem in trying to free the handle
2237                     * (for example, can't reach rpcd).
2238                     */
2239#ifdef DEBUG
2240                    if (temp_status != rpc_s_ok)
2241                    {
2242                        RPC_DBG_PRINTF (rpc_e_dbg_general, 1,
2243                                        ("(ep_get_endpoint) call_rep->none binding_rep->%p ept_lookup_handle_free returned %x\n",
2244                                         binding_r, temp_status));
2245                    }
2246#endif
2247                }
2248            }
2249        }
2250        DCETHREAD_CATCH_ALL(THIS_CATCH)
2251        {
2252            /*
2253             * Report any exception as:
2254             */
2255            *st = rpc_s_rpcd_comm_failure;
2256        }
2257        DCETHREAD_ENDTRY
2258
2259        if (*st != rpc_s_ok)
2260        {
2261            goto CLEANUP;
2262        }
2263
2264        /*
2265         * From the returned compatible towers, randomly pick one.
2266         */
2267        tower_to_use = RPC_RANDOM_GET (0, num_towers - 1);
2268
2269        assert (&towers[tower_to_use] != NULL);
2270        rpc__naf_tower_flrs_to_addr (
2271            &(towers[tower_to_use]->tower_octet_string[0]),
2272            &tower_rpc_addr,
2273            st);
2274
2275        if (*st != rpc_s_ok)
2276        {
2277            goto CLEANUP;
2278        }
2279
2280        rpc__naf_addr_inq_endpoint (tower_rpc_addr, &endpoint, st);
2281
2282        if (*st != rpc_s_ok)
2283        {
2284            goto CLEANUP;
2285        }
2286
2287        /*
2288         * The binding currently contains the rpcd boot time.
2289         * To avoid a "wrong boot time" error over dg when the
2290         * returned binding (with selected endpoint) is used to make
2291         * a rpc, reset the binding (before adding the server
2292         * endpoint) to clear the boot time.
2293         */
2294        rpc_binding_reset ((rpc_binding_handle_t) binding_r, st);
2295
2296        if (*st != rpc_s_ok)
2297        {
2298            goto CLEANUP;
2299        }
2300
2301        rpc__naf_addr_set_endpoint (endpoint, rpc_addr, st);
2302
2303        if (*st != rpc_s_ok)
2304        {
2305            goto CLEANUP;
2306        }
2307
2308        /*
2309         * Resetting the binding also reset the has-endpoint flag.
2310         * We need to turn it back on.
2311         */
2312        binding_r->addr_has_endpoint = true;
2313
2314#ifdef DEBUG
2315        RPC_DBG_PRINTF (rpc_e_dbg_general, 1,
2316                        ("(ep_get_endpoint) call_rep->none binding_rep->%p endpoint mapper returned %s\n",
2317                         binding_r, endpoint));
2318#endif
2319
2320        /*
2321         * Notify the protocol service that the binding has changed.
2322         */
2323        (*rpc_g_protocol_id[binding_r->protocol_id].binding_epv
2324         ->binding_changed) (binding_r, st);
2325
2326        if (*st != rpc_s_ok)
2327        {
2328            goto CLEANUP;
2329        }
2330
2331        full_restore_flag = false;
2332    }
2333
2334CLEANUP:
2335
2336    /*
2337     * If an error occurred, restore the caller's binding back to
2338     * its original condition before returning.
2339     */
2340    if (full_restore_flag)
2341    {
2342        binding_r->addr_has_endpoint = false;
2343        rpc__naf_addr_set_endpoint ((unsigned_char_p_t) "", rpc_addr,
2344            &temp_status);
2345    }
2346
2347    if (towers != NULL)
2348    {
2349        for (i = 0; i < num_towers; ++i)
2350        {
2351            if (towers[i] != NULL)
2352            {
2353                rpc__ep_mem_free (NULL, (dce_pointer_t) towers[i]);
2354            }
2355        }
2356
2357        RPC_MEM_FREE (towers, RPC_C_MEM_TOWER);
2358    }
2359
2360    /*
2361     * Free allocated protocol version
2362     */
2363    if (free_prot_version == true)
2364    {
2365        rpc__binding_prot_version_free (&(binding_r->protocol_version));
2366    }
2367
2368    /*
2369     * Restore the saved auth info.
2370     */
2371    binding_r->auth_info = saved_auth_info;
2372
2373    /*
2374     * Restore the saved binding com timeout.
2375     */
2376    rpc_mgmt_set_com_timeout ((rpc_binding_handle_t) binding_r,
2377                              saved_timeout, &temp_status);
2378
2379    if (temp_status != rpc_s_ok)
2380    {
2381        goto EXIT;
2382    }
2383
2384    /*
2385     * Restore the saved binding object UUID.
2386     */
2387    rpc_binding_set_object ((rpc_binding_handle_t) binding_r,
2388                            &saved_object_uuid, &temp_status);
2389
2390    if (temp_status != rpc_s_ok)
2391    {
2392        goto EXIT;
2393    }
2394
2395    if (map_tower != NULL)
2396    {
2397        rpc__tower_free (&map_tower, &temp_status);
2398
2399        if (temp_status != rpc_s_ok)
2400        {
2401            goto EXIT;
2402        }
2403    }
2404
2405    if (tower_vector != NULL)
2406    {
2407        rpc__tower_ref_vec_free (&tower_vector, &temp_status);
2408
2409        if (temp_status != rpc_s_ok)
2410        {
2411            goto EXIT;
2412        }
2413    }
2414
2415    if (tower_rpc_addr != NULL)
2416    {
2417        rpc__naf_addr_free (&tower_rpc_addr, &temp_status);
2418
2419        if (temp_status != rpc_s_ok)
2420        {
2421            goto EXIT;
2422        }
2423    }
2424
2425    if (endpoint != NULL)
2426    {
2427        rpc_string_free (&endpoint, &temp_status);
2428
2429        if (temp_status != rpc_s_ok)
2430        {
2431            goto EXIT;
2432        }
2433    }
2434
2435EXIT:
2436    if (*st != rpc_s_ok)
2437    {
2438        return;
2439    }
2440    else
2441    {
2442        *st = temp_status;
2443        return;
2444    }
2445}
2446
2447/*
2448**++
2449**
2450**  ROUTINE NAME:       rpc__ep_mem_alloc
2451**
2452**  SCOPE:              INTERNAL
2453**
2454**  DESCRIPTION:
2455**
2456**  Wrapper around RPC_MEM_ALLOC to use in call to
2457**  rpc_ss_swap_client_alloc_free.
2458**
2459**  INPUTS:
2460**
2461**      size            number of bytes to allocate
2462**
2463**  INPUTS/OUTPUTS:     none
2464**
2465**  OUTPUTS:            none
2466**
2467**  IMPLICIT INPUTS:    none
2468**
2469**  IMPLICIT OUTPUTS:   none
2470**
2471**  FUNCTION VALUE:     idl_void_p_t
2472**
2473**      return          pointer to allocated storage
2474**
2475**  SIDE EFFECTS:       none
2476**
2477**--
2478**/
2479
2480INTERNAL idl_void_p_t rpc__ep_mem_alloc
2481(
2482 idl_void_p_t	      context ATTRIBUTE_UNUSED,
2483 idl_size_t           size
2484)
2485{
2486    idl_void_p_t             ptr;
2487
2488    RPC_MEM_ALLOC (
2489        ptr,
2490        idl_void_p_t,
2491        size,
2492        RPC_C_MEM_TOWER,
2493        RPC_C_MEM_WAITOK);
2494
2495    return (ptr);
2496}
2497
2498/*
2499**++
2500**
2501**  ROUTINE NAME:       rpc__ep_mem_free
2502**
2503**  SCOPE:              INTERNAL
2504**
2505**  DESCRIPTION:
2506**
2507**  Wrapper around RPC_MEM_FREE to use in call to
2508**  rpc_ss_swap_client_alloc_free.
2509**
2510**  INPUTS:
2511**
2512**      ptr             storage to free
2513**
2514**  INPUTS/OUTPUTS:     none
2515**
2516**  OUTPUTS:            none
2517**
2518**  IMPLICIT INPUTS:    none
2519**
2520**  IMPLICIT OUTPUTS:   none
2521**
2522**  FUNCTION VALUE:     none
2523**
2524**  SIDE EFFECTS:       none
2525**
2526**--
2527**/
2528
2529INTERNAL void rpc__ep_mem_free
2530(
2531  idl_void_p_t         context ATTRIBUTE_UNUSED,
2532  dce_pointer_t            ptr
2533)
2534{
2535    RPC_MEM_FREE (ptr, RPC_C_MEM_TOWER);
2536}
2537