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**      cnbind.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  The NCA Connection Protocol Service's Binding Service.
90**
91**
92*/
93
94#include <commonp.h>    /* Common declarations for all RPC runtime */
95#include <com.h>        /* Common communications services */
96#include <comprot.h>    /* Common protocol services */
97#include <cnp.h>        /* NCA Connection private declarations */
98#include <cnpkt.h>	/* NCA Connection packet encoding */
99#include <cnassoc.h>    /* NCA Connection association service */
100#include <cnid.h>       /* NCA Connection local id service */
101#include <cnbind.h>
102
103
104/*
105**++
106**
107**  ROUTINE NAME:       rpc__cn_binding_alloc
108**
109**  SCOPE:              PRIVATE - declared in cnbind.h
110**
111**  DESCRIPTION:
112**
113**      This routine will allocate a binding rep data structure. A
114**      binding rep contains a protocol specific part and therefore
115**      must be allocated by the protocol service.
116**
117**  INPUTS:
118**
119**      is_server       Boolean indicating server-side binding handle should
120**                      be created.
121**
122**  INPUTS/OUTPUTS:     none
123**
124**  OUTPUTS:
125**
126**      st              The return status of this routine.
127**
128**  IMPLICIT INPUTS:    none
129**
130**  IMPLICIT OUTPUTS:   none
131**
132**  FUNCTION VALUE:
133**
134**      return          The allocated binding rep structure.
135**      rpc_s_ok
136**
137**  SIDE EFFECTS:       none
138**
139**--
140**/
141
142PRIVATE rpc_binding_rep_t *rpc__cn_binding_alloc
143(
144  boolean32               is_server,
145  unsigned32              *st
146)
147{
148    rpc_cn_binding_rep_p_t brp;
149
150    CODING_ERROR (st);
151
152    /*
153     * A server binding is allocated from the receiver thread which
154     * has already acquired the CN global mutex.
155     */
156    if (!is_server)
157    {
158        RPC_CN_LOCK ();
159    }
160    else
161    {
162        RPC_CN_LOCK_ASSERT ();
163    }
164
165    /*
166     * Allocate a binding rep off the lookaside list.
167     */
168    brp = (rpc_cn_binding_rep_p_t)
169        rpc__list_element_alloc (&rpc_g_cn_binding_lookaside_list,
170                                 true);
171    if (brp == NULL)
172    {
173        *st = rpc_s_no_memory;
174        RPC_CN_UNLOCK ();
175        return NULL;
176    }
177    if (!is_server)
178    {
179        ((rpc_cn_binding_rep_t *)brp)->being_resolved = false;
180        RPC_CN_UNLOCK ();
181    }
182
183    brp->common.rpc_addr = NULL;
184    brp->common.auth_info = NULL;
185    brp->common.transport_info = NULL;
186
187    *st = rpc_s_ok;
188    return ((rpc_binding_rep_p_t) brp);
189}
190
191
192/*
193**++
194**
195**  ROUTINE NAME:       rpc__cn_binding_init
196**
197**  SCOPE:              PRIVATE - declared in cnbind.h
198**
199**  DESCRIPTION:
200**
201**      This routine will initialize the protocol specific part of a
202**      previously allocated binding rep data structure. For the NCA
203**      Connection protocol this means locating an association group
204**      whose primary address matches that in the binding rep. Note
205**      that this can only be done if an RPC address is supplied.
206**
207**  INPUTS:
208**
209**      binding_r       The binding rep to be initialized.
210**
211**  INPUTS/OUTPUTS:     none
212**
213**  OUTPUTS:
214**
215**      st              The return status of this routine.
216**
217**  IMPLICIT INPUTS:    none
218**
219**  IMPLICIT OUTPUTS:   none
220**
221**  FUNCTION VALUE:
222**
223**      rpc_s_coding_error
224**      rpc_s_ok
225**
226**  SIDE EFFECTS:       none
227**
228**--
229**/
230
231PRIVATE void rpc__cn_binding_init
232(
233 rpc_binding_rep_p_t     binding_r,
234 unsigned32              *st
235)
236{
237    unsigned32                  type;
238    rpc_cn_local_id_t           grp_id;
239
240    CODING_ERROR (st);
241
242    /*
243     * Determine the type of association group we are looking for.
244     */
245    if (RPC_BINDING_IS_SERVER (binding_r))
246    {
247        //type = RPC_C_CN_ASSOC_GRP_SERVER;
248    }
249    else
250    {
251        type = RPC_C_CN_ASSOC_GRP_CLIENT;
252
253        /*
254         * Use the RPC address contained in the binding rep to find an
255         * association group.
256         */
257        RPC_CN_LOCK ();
258        grp_id = rpc__cn_assoc_grp_lkup_by_addr (binding_r->rpc_addr,
259                                                 binding_r->transport_info,
260                                                 type,
261                                                 st);
262
263        /*
264         * Record its the association group id returned into the
265         * binding rep. Note that the group id returned may be invalid.
266         */
267        ((rpc_cn_binding_rep_t *)binding_r)->grp_id = grp_id;
268        RPC_CN_UNLOCK ();
269    }
270
271    /*
272     * Return a good status code no matter what happened.
273     */
274    *st = rpc_s_ok;
275}
276
277
278/*
279**++
280**
281**  ROUTINE NAME:       rpc__cn_binding_reset
282**
283**  SCOPE:              PRIVATE - declared in cnbind.h
284**
285**  DESCRIPTION:
286**
287**      This routine will clear the endpoint in the RPC address
288**      contained in the binding rep data structure given.
289**
290**  INPUTS:
291**
292**      binding_r       The binding rep containing the RPC address
293**                      to be reset.
294**
295**  INPUTS/OUTPUTS:     none
296**
297**  OUTPUTS:
298**
299**      st              The return status of this routine.
300**
301**  IMPLICIT INPUTS:    none
302**
303**  IMPLICIT OUTPUTS:   none
304**
305**  FUNCTION VALUE:
306**
307**      rpc_s_coding_error
308**      rpc_s_ok
309**
310**  SIDE EFFECTS:       none
311**
312**--
313**/
314
315PRIVATE void rpc__cn_binding_reset
316(
317  rpc_binding_rep_p_t     binding_r,
318  unsigned32              *st
319)
320{
321    CODING_ERROR (st);
322
323    /*
324     * The endpoint in the binding is being reset. Since we assume
325     * endpoints are tied to address spaces and an association group
326     * id identifies an address space we should reset the group ID.
327     * When the endpoint is added to the binding
328     * rpc__cn_binding_init should be called again to set the group id.
329     */
330    RPC_CN_LOCAL_ID_CLEAR (((rpc_cn_binding_rep_t *)binding_r)->grp_id);
331
332    *st = rpc_s_ok;
333}
334
335
336/*
337**++
338**
339**  ROUTINE NAME:       rpc__cn_binding_changed
340**
341**  SCOPE:              PRIVATE - declared in cnbind.h
342**
343**  DESCRIPTION:
344**
345**      This routine is called when something in the common part of
346**      the binding rep given has changed.
347**
348**  INPUTS:
349**
350**      binding_r       The binding rep which changed.
351**
352**  INPUTS/OUTPUTS:     none
353**
354**  OUTPUTS:
355**
356**      st              The return status of this routine.
357**
358**  IMPLICIT INPUTS:    none
359**
360**  IMPLICIT OUTPUTS:   none
361**
362**  FUNCTION VALUE:
363**
364**      rpc_s_coding_error
365**      rpc_s_ok
366**
367**  SIDE EFFECTS:       none
368**
369**--
370**/
371
372PRIVATE void rpc__cn_binding_changed
373(
374  rpc_binding_rep_p_t     binding_r,
375  unsigned32              *st
376)
377{
378    CODING_ERROR (st);
379
380    /*
381     * The exact field which changed is not known. Init the binding.
382     */
383    rpc__cn_binding_init (binding_r, st);
384}
385
386
387/*
388**++
389**
390**  ROUTINE NAME:       rpc__cn_binding_free
391**
392**  SCOPE:              PRIVATE - declared in cnbind.h
393**
394**  DESCRIPTION:
395**
396**      This routine frees the binding rep data structure given.
397**
398**  INPUTS:             none
399**
400**  INPUTS/OUTPUTS:
401**
402**      binding_r       The binding rep to be freed
403**
404**  OUTPUTS:
405**
406**      st              The return status of this routine.
407**
408**  IMPLICIT INPUTS:    none
409**
410**  IMPLICIT OUTPUTS:   none
411**
412**  FUNCTION VALUE:
413**
414**      rpc_s_coding_error
415**      rpc_s_ok
416**
417**  SIDE EFFECTS:       none
418**
419**--
420**/
421
422PRIVATE void rpc__cn_binding_free
423(
424  rpc_binding_rep_p_t     *binding_r,
425  unsigned32              *st
426)
427{
428    CODING_ERROR (st);
429
430    RPC_CN_LOCK_ASSERT ();
431
432    /*
433     * Put the binding rep back on the lookaside list.
434     */
435    rpc__list_element_free (&rpc_g_cn_binding_lookaside_list,
436                            (dce_pointer_t) *binding_r);
437
438    /*
439     * Null the caller's pointer to this memory.
440     */
441    *binding_r = NULL;
442    *st = rpc_s_ok;
443}
444
445
446/*
447**++
448**
449**  ROUTINE NAME:       rpc__cn_binding_inq_addr
450**
451**  SCOPE:              PRIVATE - declared in cnbind.h
452**
453**  DESCRIPTION:
454**
455**      This routine allocates and returns the RPC address
456**      associated with the binding rep data structure given.
457**
458**  INPUTS:
459**
460**      binding_r       The binding rep to be freed
461**
462**  INPUTS/OUTPUTS:
463**
464**      rpc_addr        The RPC address which is allocated.
465**
466**  OUTPUTS:
467**
468**      st              The return status of this routine.
469**
470**  IMPLICIT INPUTS:    none
471**
472**  IMPLICIT OUTPUTS:   none
473**
474**  FUNCTION VALUE:
475**
476**      rpc_s_coding_error
477**      rpc_s_ok
478**      rpc_s_assoc_grp_not_found
479**
480**  SIDE EFFECTS:       none
481**
482**--
483**/
484
485PRIVATE void rpc__cn_binding_inq_addr
486(
487  rpc_binding_rep_p_t     binding_r,
488  rpc_addr_p_t            *rpc_addr,
489  unsigned32              *st
490)
491{
492    unsigned32          type;
493    rpc_cn_local_id_t   grp_id;
494    rpc_cn_assoc_grp_t  *assoc_grp;
495    rpc_protseq_id_t    protseq_id;
496
497    CODING_ERROR (st);
498
499    /*
500     * Determine the type of association group we are looking for.
501     */
502    if (RPC_BINDING_IS_SERVER (binding_r))
503    {
504        type = RPC_C_CN_ASSOC_GRP_SERVER;
505    }
506    else
507    {
508        type = RPC_C_CN_ASSOC_GRP_CLIENT;
509    }
510
511    /*
512     * Use the group id contained in the binding rep to find an
513     * association group.
514     */
515    RPC_CN_LOCK ();
516    grp_id = rpc__cn_assoc_grp_lkup_by_id (
517                 ((rpc_cn_binding_rep_t *)binding_r)->grp_id,
518                 type,
519                 binding_r->transport_info,
520                 st);
521
522    /*
523     * Check whether an association group was found or not.
524     */
525    if (RPC_CN_LOCAL_ID_VALID (grp_id))
526    {
527        /*
528         * An association group was found. Check whether it
529         * contains an RPC address.
530         */
531        assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
532        assert(assoc_grp != NULL);
533        if (assoc_grp->grp_address != NULL)
534        {
535            /*
536             * The association group contains an RPC address.
537             * Copy it into the binding.
538             */
539            rpc__naf_addr_copy (assoc_grp->grp_address,
540                                rpc_addr,
541                                st);
542        }
543        else
544        {
545            /*
546             * The association doesn't have an RPC address. Find
547             * it out using one of the connections attached to the
548             * association group.
549             */
550            rpc__naf_desc_inq_protseq_id
551                (((rpc_cn_assoc_t *)assoc_grp->grp_assoc_list.next)->cn_ctlblk.cn_sock,
552                 RPC_C_PROTOCOL_ID_NCACN,
553                 &protseq_id,
554                 st);
555            if (*st == rpc_s_ok)
556            {
557                rpc__naf_desc_inq_peer_addr
558                    (((rpc_cn_assoc_t *)assoc_grp->grp_assoc_list.next)->cn_ctlblk.cn_sock,
559                     protseq_id,
560                     rpc_addr,
561                     st);
562                if (*st == rpc_s_ok)
563                {
564                    rpc__naf_addr_copy (*rpc_addr,
565                                        &assoc_grp->grp_address,
566                                        st);
567                }
568            }
569        }
570        binding_r->rpc_addr = *rpc_addr;
571    }
572    else
573    {
574        *st = rpc_s_connection_closed;
575    }
576    RPC_CN_UNLOCK ();
577}
578
579
580/*
581**++
582**
583**  ROUTINE NAME:       rpc__cn_binding_inq_client
584**
585**  SCOPE:              PRIVATE - declared in cnbind.h
586**
587**  DESCRIPTION:
588**
589**      This routine returns the client process identifier, i.e. the
590**      association group id, for a given binding rep.
591**
592**  INPUTS:
593**
594**      binding_r       The binding rep to be freed
595**
596**  INPUTS/OUTPUTS:
597**
598**      rpc_addr        The RPC address which is allocated.
599**
600**  OUTPUTS:
601**
602**      st              The return status of this routine.
603**
604**  IMPLICIT INPUTS:    none
605**
606**  IMPLICIT OUTPUTS:   none
607**
608**  FUNCTION VALUE:
609**
610**      rpc_s_coding_error
611**      rpc_s_ok
612**
613**  SIDE EFFECTS:       none
614**
615**--
616**/
617
618PRIVATE void rpc__cn_binding_inq_client
619(
620  rpc_binding_rep_p_t     binding_r,
621  rpc_client_handle_t     *client_h,
622  unsigned32              *st
623)
624{
625    rpc_cn_local_id_t   grp_id;
626
627    CODING_ERROR (st);
628
629    /*
630     * Get the association group id from the binding rep.
631     */
632    grp_id = ((rpc_cn_binding_rep_t *)binding_r)->grp_id;
633
634    /*
635     * Make sure the group id is valid.
636     */
637    *client_h = (rpc_client_handle_t) grp_id.all;
638    if (RPC_CN_LOCAL_ID_VALID (grp_id))
639    {
640        *st = rpc_s_ok;
641    }
642    else
643    {
644        *st = rpc_s_invalid_binding;
645    }
646}
647
648/*
649**++
650**
651**  ROUTINE NAME:       rpc__cn_binding_copy
652**
653**  SCOPE:              PRIVATE - declared in cnbind.h
654**
655**  DESCRIPTION:
656**
657**      This routine will init the CN specific fields of a copied
658**      binding rep.
659**
660**  INPUTS:
661**
662**      src_binding_r   The binding rep to be copied.
663**      dst_binding_r   The binding rep being copied into.
664**
665**  INPUTS/OUTPUTS:     none
666**
667**  OUTPUTS:
668**
669**      st              The return status of this routine.
670**
671**  IMPLICIT INPUTS:    none
672**
673**  IMPLICIT OUTPUTS:   none
674**
675**  FUNCTION VALUE:
676**
677**      rpc_s_coding_error
678**      rpc_s_ok
679**
680**  SIDE EFFECTS:       none
681**
682**--
683**/
684
685PRIVATE void rpc__cn_binding_copy
686(
687  rpc_binding_rep_p_t     src_binding_r,
688  rpc_binding_rep_p_t     dst_binding_r,
689  unsigned32              *st
690)
691{
692    CODING_ERROR (st);
693
694    /*
695     * Get the association group id from the src binding rep and put
696     * it in the dst binding rep.
697     */
698    ((rpc_cn_binding_rep_t *)dst_binding_r)->grp_id =
699        ((rpc_cn_binding_rep_t *)src_binding_r)->grp_id;
700
701    *st = rpc_s_ok;
702}
703
704
705/*
706**++
707**
708**  ROUTINE NAME:       rpc__cn_binding_cross_fork
709**
710**  SCOPE:              PRIVATE - declared in cnbind.h
711**
712**  DESCRIPTION:
713**
714**      This routine makes it possible for children of forks to use
715**      binding handles inherited from their parents.
716**
717**  INPUTS:
718**
719**      binding_r       The binding rep to be inherited
720**
721**  INPUTS/OUTPUTS:     none
722**
723**  OUTPUTS:
724**
725**      st              The return status of this routine.
726**
727**  IMPLICIT INPUTS:    none
728**
729**  IMPLICIT OUTPUTS:   none
730**
731**  FUNCTION VALUE:
732**
733**      rpc_s_coding_error
734**      rpc_s_ok
735**
736**  SIDE EFFECTS:       none
737**
738**--
739**/
740
741PRIVATE void rpc__cn_binding_cross_fork
742(
743  rpc_binding_rep_p_t     binding_r ATTRIBUTE_UNUSED,
744  unsigned32              *st
745)
746{
747    CODING_ERROR (st);
748
749    /*
750     * This is a dummy function to avoid the null reference
751     * causing a core dump.
752     */
753
754    *st = rpc_s_ok;
755}
756