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**      rpcdepdb.c
82**
83**  FACILITY:
84**
85**      RPC Daemon
86**
87**  ABSTRACT:
88**
89**  Generic Endpoint Database Management, Forwarding,
90**  and Lookup Routines
91**
92**
93*/
94
95#include <commonp.h>
96#include <com.h>
97#include <comp.h>
98
99#include <dce/ep.h>     /* derived from ep.idl */
100#include <dce/mgmt.h>   /* derived from mgmt.idl */
101#include <dsm.h>        /* derived from dsm.idl */
102
103#include <rpcdp.h>
104#include <rpcddb.h>
105#include <rpcdepdb.h>
106#include <rpcdepdbp.h>
107#include <rpcdutil.h>
108
109#include <comtwr.h>
110
111/*
112 * The server supports a single endpoint location database.
113 */
114INTERNAL epdb_handle_t    epdb_handle = NULL;
115
116/*
117 * The current version of the persistent database file (the value in a file_hdr).
118 */
119#define epdb_c_file_version 8
120
121INTERNAL void epdb_recreate_lists
122    (
123        struct db       *h,
124        error_status_t  *status
125    );
126
127INTERNAL void epdb_chk_entry
128    (
129        ept_entry_p_t   xentry,
130        twr_fields_p_t  tfp,
131        rpc_addr_p_t    addr,
132        error_status_t  *status
133    );
134
135INTERNAL void epdb_chk_map_entry
136    (
137        twr_fields_p_t  tfp,
138        error_status_t  *status
139    );
140
141INTERNAL void epdb_to_ept
142    (
143        db_entry_p_t    entp,
144        ept_entry_t     *xentry,
145        error_status_t  *status
146    );
147
148INTERNAL void epdb_insert_entry
149    (
150        struct db       *h,
151        ept_entry_p_t   xentry,
152        twr_fields_p_t  tfp,
153        rpc_addr_p_t    addr,
154        db_entry_p_t    *entp,
155        error_status_t  *status
156    );
157
158INTERNAL void epdb_replace_entry
159    (
160        struct db       *h,
161        ept_entry_p_t   xentry,
162        db_entry_p_t    entp,
163        error_status_t  *status
164    );
165
166INTERNAL boolean32 epdb_is_replace_candidate
167    (
168        db_entry_t      *entp,
169        uuid_p_t        object,
170        twr_fields_p_t  tfp,
171        rpc_addr_p_t    addr
172    );
173
174INTERNAL void epdb_delete_replaceable_entries
175    (
176        struct db       *h,
177        uuid_p_t        object,
178        twr_fields_p_t  tfp,
179        rpc_addr_p_t    addr,
180        error_status_t  *status
181    );
182
183INTERNAL void epdb_delete_entries_by_obj_if_addr
184    (
185        struct db           *h,
186        boolean32           object_speced,
187        uuid_p_t            object,
188        rpc_if_id_p_t       interface,
189        rpc_addr_p_t        addr,
190        error_status_t      *status
191    );
192
193INTERNAL db_entry_t *epdb_lookup_entry
194    (
195        struct db       *h,
196        ept_entry_p_t   xentry
197    );
198
199INTERNAL void lookup
200    (
201        struct db           *h,
202        unsigned32          inquiry_type,
203        uuid_p_t            object,
204        rpc_if_id_p_t       interface,
205        unsigned32          vers_option,
206        ept_lookup_handle_t *entry_handle,
207        unsigned32          max_ents,
208        unsigned32          *num_ents,
209        ept_entry_t         entries[],
210        error_status_t      *status
211    );
212
213INTERNAL void lookup_match
214    (
215        unsigned32          inquiry_type,
216        uuid_p_t            object,
217        rpc_if_id_p_t       interface,
218        unsigned32          vers_option,
219        unsigned32          max_ents,
220        unsigned32          *num_ents,
221        ept_entry_t         entries[],
222        unsigned32          list_type,
223        db_lists_t          **lpp,
224        error_status_t      *status
225    );
226
227INTERNAL void map
228    (
229        struct db           *h,
230        uuid_p_t            object,
231        rpc_if_id_p_t       interface,
232        rpc_syntax_id_p_t   data_rep,
233        rpc_protocol_id_t   rpc_protocol,
234        unsigned32          rpc_protocol_vers_major,
235        unsigned32          rpc_protocol_vers_minor,
236        rpc_protseq_id_t    protseq,
237        ept_lookup_handle_t *map_handle,
238        unsigned32          max_ents,
239        unsigned32          *n_ents,
240        db_entry_t          *db_entries[],
241        unsigned32          *status
242    );
243
244INTERNAL void map_match
245    (
246        uuid_p_t            object,
247        rpc_if_id_p_t       interface,
248        rpc_syntax_id_p_t   data_rep,
249        rpc_protocol_id_t   rpc_protocol,
250        unsigned32          rpc_protocol_vers_major,
251        unsigned32          rpc_protocol_vers_minor,
252        rpc_protseq_id_t    protseq,
253        unsigned32          max_ents,
254        unsigned32          *n_ents,
255        db_entry_t          *entries[],
256        ept_lookup_handle_t *map_handle,
257        unsigned32          pass,
258        db_list_type_t      list,
259        db_lists_t          **lpp,
260        unsigned32          *status
261    );
262
263INTERNAL void map_mgmt
264    (
265        struct db           *h,
266        uuid_p_t            object,
267        rpc_syntax_id_p_t   data_rep,
268        rpc_protocol_id_t   rpc_protocol,
269        unsigned32          rpc_protocol_vers_major,
270        unsigned32          rpc_protocol_vers_minor,
271        rpc_protseq_id_t    protseq,
272        ept_lookup_handle_t *map_handle,
273        unsigned32          max_ents,
274        unsigned32          *n_ents,
275        db_entry_t          *db_entries[],
276        unsigned32          *status
277    );
278
279INTERNAL void map_mgmt_match
280    (
281        uuid_p_t            object,
282        rpc_syntax_id_p_t   data_rep,
283        rpc_protocol_id_t   rpc_protocol,
284        unsigned32          rpc_protocol_vers_major,
285        unsigned32          rpc_protocol_vers_minor,
286        rpc_protseq_id_t    protseq,
287        unsigned32          max_ents,
288        unsigned32          *n_ents,
289        db_entry_t          *entries[],
290        ept_lookup_handle_t *map_handle,
291        unsigned32          pass,
292        db_list_type_t      list,
293        db_lists_t          **lpp,
294        unsigned32          *status
295    );
296
297INTERNAL boolean32 map_mgmt_endpt_unique
298    (
299        rpc_addr_p_t    addr,
300        unsigned32      n_ents,
301        db_entry_t      *entries[]
302    );
303
304
305/*
306 * Get an endpoint database handle from a handle_t.
307 *
308 * If the handle is not bound to an object (i.e. the object
309 * is nil) treat this as a request to just use "the" endpoint
310 * database.  If a specific object is specified, make sure that
311 * the object is the same as the endpoint database object.
312 * (accept a null handle to allow for "local" callers).
313 */
314PRIVATE void epdb_handle_from_ohandle(h, epdb_h, status)
315handle_t        h;
316epdb_handle_t   *epdb_h;
317error_status_t  *status;
318{
319    idl_uuid_t  obj;
320    idl_uuid_t  epdb_obj;
321
322    SET_STATUS(status, rpc_s_ok);
323
324    if (h == NULL)
325    {
326        *epdb_h = epdb_handle;
327        return;
328    }
329
330    rpc_binding_inq_object(h, &obj, status);
331    if (uuid_is_nil(&obj, status))
332        *epdb_h = epdb_handle;
333    else
334    {
335        epdb_inq_object(epdb_handle, &epdb_obj, status);
336        if (uuid_equal(&obj, &epdb_obj, status))
337            *epdb_h = epdb_handle;
338        else
339            SET_STATUS(status, ept_s_cant_perform_op); /* !!! ep_wrong_object? */
340    }
341    return;
342}
343
344/*  Return the handle to the ep database
345 *  Since there's only one database just return what's in
346 *  epdb_handle
347 */
348PRIVATE epdb_handle_t epdb_inq_handle()
349{
350    return(epdb_handle);
351}
352
353
354/*
355 *  Open/create a database and return a handle to it.
356 *  Init the database lists and lock.  Start the task
357 *  to check server liveness and to purge entries that
358 *  are marked as deleted.
359 */
360PRIVATE epdb_handle_t epdb_init(pathname, status)
361unsigned char   *pathname;
362error_status_t  *status;
363{
364    struct db *h;
365
366    SET_STATUS_OK(status);
367
368    h = (struct db *) malloc(sizeof(struct db));
369    if (h == NULL) {
370        SET_STATUS(status, ept_s_cant_perform_op);
371        return(NULL);
372    }
373
374    h->dsh = NULL;
375
376    db_init_lists(h);
377
378    db_open(h, pathname, epdb_c_file_version, status);
379    if (! STATUS_OK(status))
380    {
381        /* Try deleting and recreating the database */
382        unlink(pathname);
383        db_open(h, pathname, epdb_c_file_version, status);
384        if (! STATUS_OK(status))
385        {
386            return NULL;
387        }
388    }
389
390    /*  Database now exists, recreate its lists
391     */
392    epdb_recreate_lists(h, status);
393    if (! STATUS_OK(status)) return(NULL);
394
395    db_init_lock(h);
396
397    sliv_init(h, status);
398    if (! STATUS_OK(status)) return(NULL);
399
400    epdb_handle = (epdb_handle_t) h;
401
402    return((epdb_handle_t) h);
403}
404
405INTERNAL void epdb_recreate_lists(h, status)
406struct db       *h;
407error_status_t  *status;
408{
409    db_entry_t      *entp = NULL;
410    dsm_marker_t    marker;      /* DSM datastore traversal marker */
411
412    dsm_marker_reset(&marker);
413
414    while(true)
415    {
416        void* _entp = NULL;
417        dsm_read(h->dsh,&marker, &_entp,status);    /* get next record */
418        entp = (db_entry_t*) _entp;
419        if (! STATUS_OK(status))
420        {
421            if (*status == dsm_err_no_more_entries)
422            {
423                SET_STATUS(status, error_status_ok);
424            }
425            else
426            {
427                if (dflag)
428                    show_st("Error reading ept database", status);
429                SET_STATUS(status, ept_s_cant_access);
430            }
431            return;
432        }
433
434        tower_to_addr(&entp->tower, &entp->addr, status);
435        if (! STATUS_OK(status))
436        {
437            if (dflag)
438                show_st("tower_to_addr error for ept entry", status);
439
440            SET_STATUS(status, ept_s_invalid_entry);
441            return;
442        }
443
444        entp->read_nrefs = 0;
445        entp->ncomm_fails = 0;
446
447        db_lists_add(h, entp);
448    }
449}
450
451
452/*
453 *  epdb_chk_entry - check an entry that is about to be inserted
454 *  into the ep database
455 *  All tower floors in an entry must be valid and non-nil
456 *  (eg. nil interface uuid is prohibited).  Also, check tower
457 *  via rpc_tower_to_binding - sliv tasks will need to get binding
458 *  handle
459 */
460INTERNAL void epdb_chk_entry(xentry, tfp, addr, status)
461ept_entry_p_t   xentry;
462twr_fields_p_t  tfp;
463rpc_addr_p_t    addr;
464error_status_t  *status;
465{
466    rpc_binding_handle_t    binding_h;
467    error_status_t          tmp_st;
468
469    if (uuid_is_nil(&tfp->interface.uuid, &tmp_st) ||
470        uuid_is_nil(&tfp->data_rep.id, &tmp_st) ||
471        (addr == NULL) ||
472        (addr->len == 0))
473    {
474        SET_STATUS(status, ept_s_invalid_entry);
475        return;
476    }
477
478    rpc_tower_to_binding(xentry->tower->tower_octet_string, &binding_h, status);
479    if (! STATUS_OK(status)) return;
480
481    rpc_binding_free(&binding_h, &tmp_st);
482}
483
484INTERNAL void epdb_chk_map_entry(tfp, status)
485twr_fields_p_t  tfp;
486error_status_t  *status;
487{
488    error_status_t  tmp_st;
489
490    assert (status != NULL);
491    if (uuid_is_nil(&tfp->interface.uuid, &tmp_st) ||
492        uuid_is_nil(&tfp->data_rep.id, &tmp_st) ||
493        (! RPC_PROTSEQ_INQ_SUPPORTED(tfp->protseq)) )
494        SET_STATUS(status, ept_s_invalid_entry);
495    else
496        SET_STATUS_OK(status);
497}
498
499INTERNAL void epdb_to_ept(entp, xentry, status)
500db_entry_p_t    entp;
501ept_entry_t     *xentry;
502error_status_t  *status;
503{
504    xentry->object = entp->object;
505    memcpy((char *)xentry->annotation, (char *)entp->annotation,
506        sizeof(xentry->annotation));
507
508    tower_ss_copy(&entp->tower, &xentry->tower, status);
509}
510
511/*  epdb_insert_entry
512 *  Allocate dsm storage for an entry in the endpoint database
513 *  Fill the entry from xentry, tfp, and addr
514 *  Write it to disk
515 *  Add entry to various lists
516 *  Return db pointer to entry in entp
517 */
518INTERNAL void epdb_insert_entry(h, xentry, tfp, addr, entp, status)
519struct db       *h;
520ept_entry_p_t   xentry;
521twr_fields_p_t  tfp;
522rpc_addr_p_t    addr;
523db_entry_p_t    *entp;
524error_status_t  *status;
525{
526    db_entry_t      *db_entp;
527    error_status_t  tmp_st;
528
529    dsm_allocate(h->dsh, sizeof(db_entry_t) + xentry->tower->tower_length,
530        (void **) entp, status);
531    if (! STATUS_OK(status)) return;
532
533    db_entp = *entp;
534
535    db_entp->read_nrefs = 0;
536    db_entp->ncomm_fails = 0;
537    db_entp->delete_flag = false;
538
539    db_entp->object = xentry->object;
540    db_entp->interface = tfp->interface;
541    db_entp->object_nil = uuid_is_nil(&db_entp->object, &tmp_st);
542    db_entp->if_nil = uuid_is_nil(&db_entp->interface.uuid, &tmp_st);
543    db_entp->data_rep_id = tfp->data_rep.id;
544    db_entp->data_rep_vers_major = RPC_IF_VERS_MAJOR(tfp->data_rep.version);
545    db_entp->data_rep_vers_minor = RPC_IF_VERS_MINOR(tfp->data_rep.version);
546    db_entp->rpc_protocol = tfp->rpc_protocol;
547    db_entp->rpc_protocol_vers_major = tfp->rpc_protocol_vers_major;
548    db_entp->rpc_protocol_vers_minor = tfp->rpc_protocol_vers_minor;
549    db_entp->addr = addr;
550    memcpy((char *)db_entp->annotation, (char *)xentry->annotation,
551        sizeof(db_entp->annotation));
552    db_entp->tower.tower_length = xentry->tower->tower_length;
553    memcpy((char *) db_entp->tower.tower_octet_string, (char *) xentry->tower->tower_octet_string,
554        xentry->tower->tower_length);
555
556    dsm_write(h->dsh, (void *) db_entp, status);
557    if (! STATUS_OK(status)) return;
558
559    db_lists_add(h, db_entp);
560}
561
562/*  epdb_replace_entry
563 *  Replace an existing entry - just change the annotation
564 *  because all other fields are the same
565 *  Also do some mgmt stuff - clear delete flag and ncomm_fails field
566 */
567INTERNAL void epdb_replace_entry(h, xentry, entp, status)
568struct db       *h;
569ept_entry_p_t   xentry;
570db_entry_p_t    entp;
571error_status_t  *status;
572{
573    entp->ncomm_fails = 0;
574    entp->delete_flag = false;
575    memcpy((char *)entp->annotation, (char *)xentry->annotation,
576        sizeof(entp->annotation));
577
578    db_update_entry(h, entp, status);
579}
580
581/*  epdb_delete_entry
582 *  Delete an entry from the database.
583 *
584 *  If any readers have unlocked the db but
585 *  are pointing to this entry, mark the entry
586 *  as deleted and write it to disk.
587 *  Otherwise, remove the entry from all
588 *  lists and delete it from the database
589 */
590PRIVATE void epdb_delete_entry(h, entp, status)
591struct db       *h;
592db_entry_p_t    entp;
593error_status_t  *status;
594{
595    if (entp->read_nrefs == 0)
596    {
597        db_lists_remove(h, entp);
598        rpc__naf_addr_free(&entp->addr, status);
599        dsm_free(h->dsh, (void *) entp, status);
600    }
601    else
602    {
603        entp->delete_flag = true;
604        db_update_entry(h, entp, status);
605    }
606}
607
608/*
609 *  epdb_is_replace_candidate
610 *
611 *  Return true iff the specified entry looks like a candidate for
612 *  replacement.  Requirements for candidacy are: matching object, matching
613 *  i/f UUID and major version, matching RPC protseq, matching data rep,
614 *  matching RPC protocol ID and RPC protocol major and minor version.
615 *  Candidacy is not sufficient to determine actual replaceability; i/f
616 *  minor version and network address must be considered as well.  See
617 *  below.
618 */
619INTERNAL boolean32 epdb_is_replace_candidate(entp, object, tfp, addr)
620twr_fields_p_t  tfp;
621uuid_p_t        object;
622db_entry_t      *entp;
623rpc_addr_p_t    addr;
624{
625    error_status_t      tmp_st;
626    unsigned32          data_rep_vers_major,
627                        data_rep_vers_minor;
628
629    data_rep_vers_major = RPC_IF_VERS_MAJOR(tfp->data_rep.version);
630    data_rep_vers_minor = RPC_IF_VERS_MINOR(tfp->data_rep.version);
631
632    return (uuid_equal(object, &entp->object, &tmp_st) &&
633            uuid_equal(&tfp->interface.uuid, &entp->interface.uuid, &tmp_st) &&
634            (tfp->interface.vers_major == entp->interface.vers_major) &&
635            (addr->rpc_protseq_id == entp->addr->rpc_protseq_id) &&
636            uuid_equal(&tfp->data_rep.id, &entp->data_rep_id, &tmp_st) &&
637            (data_rep_vers_major == entp->data_rep_vers_major) &&
638            (data_rep_vers_minor == entp->data_rep_vers_minor) &&
639            (tfp->rpc_protocol == entp->rpc_protocol) &&
640            (tfp->rpc_protocol_vers_major == entp->rpc_protocol_vers_major) &&
641            (tfp->rpc_protocol_vers_minor == entp->rpc_protocol_vers_minor));
642}
643
644/*
645 *  epdb_delete_replaceable_entries
646 *
647 *  Delete entries which are "replaceable" by the new entry implied by
648 *  the object, tfp, and addr parameters.
649 */
650INTERNAL void epdb_delete_replaceable_entries(h, object, tfp, addr, status)
651struct db       *h;
652uuid_p_t        object;
653twr_fields_p_t  tfp;
654rpc_addr_p_t    addr;
655error_status_t  *status;
656{
657    unsigned_char_p_t   netaddr,
658                        netaddr2;
659    db_lists_t          *lp,
660                        *lp_first,
661                        *lp_next;
662    db_list_type_t      list_type;
663    error_status_t      tmp_st;
664
665    rpc__naf_addr_inq_netaddr(addr, &netaddr, status);
666    if (! STATUS_OK(status))
667    {
668        SET_STATUS(status, ept_s_invalid_entry);
669        return;
670    }
671
672    if (! uuid_is_nil(object, &tmp_st))
673    {
674        list_type = db_c_object_list;
675        lp_first = db_list_first(&h->lists_mgmt, db_c_object_list, object);
676    }
677    else
678    {
679        list_type = db_c_interface_list;
680        lp_first = db_list_first(&h->lists_mgmt, db_c_interface_list, &tfp->interface.uuid);
681    }
682
683    /*
684     *  Scan the list and see if there are any replace candidates with an
685     *  i/f minor version that's greater than the proposed new entry.  If
686     *  there are, the replace must fail.
687     */
688    for (lp = lp_first; lp != NULL; lp = db_list_next(list_type, lp))
689    {
690        db_entry_t *entp = (db_entry_t *) lp;
691
692        if (entp->delete_flag) continue;
693
694        if (epdb_is_replace_candidate(entp, object, tfp, addr) &&
695            entp->interface.vers_minor > tfp->interface.vers_minor)
696        {
697            assert(status != NULL);
698            SET_STATUS(status, ept_s_invalid_entry);
699            goto DONE;
700        }
701    }
702
703    /*
704     *  Scan the list again and delete all replace candidates that have
705     *  network address that matches the network entry of the new entry.
706     */
707    for (lp = lp_first; lp != NULL; lp = lp_next)
708    {
709        db_entry_t *entp = (db_entry_t *) lp;
710
711        /*
712         *  Point to next entry - may remove this one from the list
713         *  and delete it
714         */
715        lp_next = db_list_next(list_type, lp);
716
717        if (entp->delete_flag) continue;
718
719        if (epdb_is_replace_candidate(entp, object, tfp, addr))
720        {
721            rpc__naf_addr_inq_netaddr(entp->addr, &netaddr2, &tmp_st);
722            if (! STATUS_OK(&tmp_st)) continue;
723
724            if (strcmp((char *) netaddr, (char *) netaddr2) == 0)
725            {
726                /*  Entry matches target in all fields except
727                 *  endpoint so delete it
728                 */
729                epdb_delete_entry(h, entp, &tmp_st);
730            }
731
732            rpc_string_free(&netaddr2, &tmp_st);
733        }
734    }
735
736    assert(status != NULL);
737    SET_STATUS_OK(status);
738
739DONE:
740
741    rpc_string_free(&netaddr, &tmp_st);
742
743}
744
745/*
746 *  epdb_delete_entries_by_obj_if_addr
747 *
748 *  Delete entries which match target object (if speced), interface, and addr
749 */
750INTERNAL void epdb_delete_entries_by_obj_if_addr(h, object_speced, object, interface, addr, status)
751struct db           *h;
752boolean32           object_speced;
753uuid_p_t            object;
754rpc_if_id_p_t       interface;
755rpc_addr_p_t        addr;
756error_status_t      *status;
757{
758    unsigned32      ndelete;
759    db_lists_t      *lp,
760                    *lp_next;
761    db_entry_t      *entp;
762    error_status_t  tmp_st;
763
764    ndelete = 0;
765
766    for (lp = db_list_first(&h->lists_mgmt, db_c_interface_list, &interface->uuid);
767            lp != NULL; lp = lp_next)
768    {
769        /*
770         *  Point to next entry - may remove this one from the list
771         *  and delete it
772         */
773        lp_next = db_list_next(db_c_interface_list, lp);
774
775        entp = (db_entry_t *) lp;
776
777        if (entp->delete_flag) continue;
778
779        if (((! object_speced) || uuid_equal(object, &entp->object, &tmp_st)) &&
780            (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st)) &&
781            (interface->vers_major == entp->interface.vers_major) &&
782            (interface->vers_minor == entp->interface.vers_minor) &&
783            (rpc__naf_addr_compare(addr, entp->addr, &tmp_st)))
784        {
785            /*  Entry matches target object (if speced),
786             *  interface, and addr so delete it
787             */
788            epdb_delete_entry(h, entp, status);
789            if (! STATUS_OK(status)) return;
790
791            ndelete++;
792        }
793    }
794
795    assert(status != NULL);
796    if (ndelete > 0)
797        SET_STATUS_OK(status);
798    else
799        SET_STATUS(status, ept_s_not_registered);
800}
801
802/*  epdb_lookup_entry
803 *  Return pointer to entry which exactly matches
804 *  xentry
805 *  Return all entries, even ones marked as deleted
806 */
807INTERNAL db_entry_t *epdb_lookup_entry(h, xentry)
808struct db       *h;
809ept_entry_p_t   xentry;
810{
811    db_entry_t      *entp;
812    db_lists_t      *lp;
813    db_list_type_t  list_type;
814    rpc_if_id_t     interface;
815    error_status_t  tmp_st;
816
817    if (! uuid_is_nil(&xentry->object, &tmp_st))
818    {
819        list_type = db_c_object_list;
820        lp = db_list_first(&h->lists_mgmt, db_c_object_list, &xentry->object);
821    }
822    else
823    {
824        tower_to_if_id(xentry->tower, &interface, &tmp_st);
825        list_type = db_c_interface_list;
826        lp = db_list_first(&h->lists_mgmt, db_c_interface_list, &interface.uuid);
827    }
828
829    for ( ; lp != NULL; lp = db_list_next(list_type, lp))
830    {
831        entp = (db_entry_t *) lp;
832
833        if (uuid_equal(&xentry->object, &entp->object, &tmp_st) &&
834            (xentry->tower->tower_length == entp->tower.tower_length) &&
835            (memcmp((char *) xentry->tower->tower_octet_string,
836                    (char *) entp->tower.tower_octet_string,
837                    xentry->tower->tower_length) == 0))
838        {
839            return(entp);
840        }
841    }
842
843    return(NULL);
844}
845
846
847/*
848 * Add a new entry to the database.  If the entry already exists simply
849 * modify its annotation field (it's the only field that might be
850 * different), clear some of its mgmt fields and update the entry
851 * on disk.
852 *
853 * Note:  All tower floors in an entry must be valid and non-nil
854 * (eg. nil interface uuid is prohibited).
855 */
856PRIVATE void epdb_insert(h_, xentry, replace, status)
857epdb_handle_t   h_;
858ept_entry_p_t   xentry;
859boolean32       replace;
860error_status_t  *status;
861{
862    struct db               *h = (struct db *) h_;
863    db_entry_t              *entp;
864    twr_fields_t            twr_fields;
865    rpc_addr_p_t            addr;
866    error_status_t          tmp_st;
867
868    addr = NULL;
869
870    /*  Parse the new entry's tower and check
871     *  whether the new entry is ok.
872     *  Prefill status to bad entry for quick return.
873     */
874    SET_STATUS(status, ept_s_invalid_entry);
875
876    /*
877     * Parse xentry's tower into twr_fields
878     */
879    tower_to_fields(xentry->tower, &twr_fields, &tmp_st);
880    if (!STATUS_OK(&tmp_st)) return;
881
882    tower_to_addr(xentry->tower, &addr, &tmp_st);
883    if (!STATUS_OK(&tmp_st)) return;
884
885    epdb_chk_entry(xentry, &twr_fields, addr, &tmp_st);
886    if (!STATUS_OK(&tmp_st))
887    {
888        if (addr != NULL) rpc__naf_addr_free(&addr, &tmp_st);
889        return;
890    }
891
892    db_lock(h);
893
894    if (replace)
895    {
896        /*  Delete entries that match
897         *  in all fields except endpoint
898         */
899        epdb_delete_replaceable_entries(h, &xentry->object, &twr_fields, addr, status);
900        if (! STATUS_OK(status))
901        {
902            rpc__naf_addr_free(&addr, &tmp_st);
903            db_unlock(h);
904            return;
905        }
906    }
907
908    entp = epdb_lookup_entry(h, xentry);
909
910    if (entp == NULL)
911    {
912        /*  New entry
913         *  insert it in dbase and add it to lists
914         */
915        epdb_insert_entry(h, xentry, &twr_fields, addr, &entp, status);
916    }
917    else
918    {
919        /*  Existing entry - just replace annotation and clear some mgmt fields
920         *  Free unused addr (already have it for this entry)
921         */
922        rpc__naf_addr_free(&addr, &tmp_st);
923
924        epdb_replace_entry(h, xentry, entp, status);
925    }
926
927    db_unlock(h);
928
929    if (! STATUS_OK(status))
930    {
931        if (addr != NULL) rpc__naf_addr_free(&addr, &tmp_st);
932        db_to_ept_ecode(status);
933    }
934}
935
936/*
937 * Remove an entry from the database.
938 * Only a database entry which exactly matches
939 * xentry is deleted.
940 */
941PRIVATE void epdb_delete(h_, xentry, status)
942epdb_handle_t   h_;
943ept_entry_p_t   xentry;
944error_status_t  *status;
945{
946    struct db       *h = (struct db *) h_;
947    db_entry_t      *entp;
948
949    SET_STATUS_OK(status);
950
951    db_lock(h);
952
953    entp = epdb_lookup_entry(h, xentry);
954
955    if (entp != NULL)
956    {
957        if (entp->delete_flag)
958            SET_STATUS(status, ept_s_not_registered);
959        else
960        {
961        /*
962         *  Matching entry found so delete it
963         */
964        epdb_delete_entry(h, entp, status);
965        if (! STATUS_OK(status)) db_to_ept_ecode(status);
966    }
967    }
968    else
969        SET_STATUS(status, ept_s_not_registered);
970
971    db_unlock(h);
972}
973
974PRIVATE void epdb_mgmt_delete(h_, object_speced, object, tower, status)
975epdb_handle_t       h_;
976boolean32           object_speced;
977uuid_p_t            object;
978twr_p_t             tower;
979error_status_t      *status;
980{
981    struct db       *h = (struct db *) h_;
982    rpc_if_id_t     interface;
983    rpc_addr_p_t    addr;
984    error_status_t  tmp_st;
985
986    SET_STATUS(status, ept_s_invalid_entry);
987
988    tower_to_if_id(tower, &interface, status);
989    if (! STATUS_OK(status)) return;
990    tower_to_addr(tower, &addr, status);
991    if (! STATUS_OK(status)) return;
992
993    db_lock(h);
994
995    epdb_delete_entries_by_obj_if_addr(h, object_speced, object, &interface, addr, status);
996    if (! STATUS_OK(status)) db_to_ept_ecode(status);
997
998    db_unlock(h);
999
1000    rpc__naf_addr_free(&addr, &tmp_st);
1001}
1002
1003
1004/*
1005 *  epdb_lookup
1006 *  Return entries that match filter speced by inquiry_type, vers_option,
1007 *  object, and interface.
1008 *
1009 */
1010PRIVATE void epdb_lookup(h_, inquiry_type, object, interface, vers_option, entry_handle, max_ents,
1011    num_ents, entries, status)
1012epdb_handle_t       h_;
1013unsigned32          inquiry_type;
1014uuid_p_t            object;
1015rpc_if_id_p_t       interface;
1016unsigned32          vers_option;
1017ept_lookup_handle_t *entry_handle;
1018unsigned32          max_ents;
1019unsigned32          *num_ents;
1020ept_entry_t         entries[];
1021error_status_t      *status;
1022{
1023    struct db       *h = (struct db *) h_;
1024
1025    *num_ents = 0;
1026
1027    /* lock database before delete_context or lookup
1028     */
1029    db_lock(h);
1030
1031    if (entries == NULL)
1032    {
1033        db_delete_context(h, entry_handle);
1034        SET_STATUS(status, ept_s_invalid_entry);
1035        db_unlock(h);
1036        return;
1037    }
1038
1039    lookup(h, inquiry_type, object, interface, vers_option, entry_handle, max_ents, num_ents, entries, status);
1040
1041    db_unlock(h);
1042}
1043
1044INTERNAL void lookup(h, inquiry_type, object, interface, vers_option, entry_handle, max_ents,
1045    num_ents, entries, status)
1046struct db           *h;
1047unsigned32          inquiry_type;
1048uuid_p_t            object;
1049rpc_if_id_p_t       interface;
1050unsigned32          vers_option;
1051ept_lookup_handle_t *entry_handle;
1052unsigned32          max_ents;
1053unsigned32          *num_ents;
1054ept_entry_t         entries[];
1055error_status_t      *status;
1056{
1057    unsigned32      pass;
1058    db_list_type_t  list_type;
1059    db_lists_t      *lp;
1060    unsigned32      i;
1061
1062    SET_STATUS_OK(status);
1063
1064    if ((entry_handle == NULL) || (*entry_handle == NULL))
1065    {
1066        /*  no context saved so init context
1067         */
1068        switch ((int)inquiry_type)
1069        {
1070            case rpc_c_ep_all_elts:
1071                pass = 1;
1072                list_type = db_c_entry_list;
1073                lp = db_list_first(&h->lists_mgmt, list_type, NULL);
1074                break;
1075
1076            case rpc_c_ep_match_by_if:
1077            case rpc_c_ep_match_by_both:
1078                pass = 1;
1079                list_type = db_c_interface_list;
1080                lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid);
1081                break;
1082
1083            case rpc_c_ep_match_by_obj:
1084                pass = 1;
1085                list_type = db_c_object_list;
1086                lp = db_list_first(&h->lists_mgmt, list_type, object);
1087                break;
1088
1089            default:
1090                *status = rpc_s_invalid_inquiry_type;
1091                return;
1092        }
1093    }
1094    else
1095    {
1096        /*  context has been saved.
1097         *  restore context
1098         */
1099        db_get_context(h, entry_handle, &list_type, &lp, &pass, status);
1100        if (! STATUS_OK(status))
1101        {
1102            *entry_handle = NULL;
1103            return;
1104        }
1105
1106        /*  do some sanity checking on inquiry_type/context info
1107         */
1108        switch ((int)inquiry_type)
1109        {
1110            case rpc_c_ep_all_elts:
1111                if (list_type != db_c_entry_list)
1112                    *status = ept_s_invalid_context;
1113                break;
1114
1115            case rpc_c_ep_match_by_if:
1116            case rpc_c_ep_match_by_both:
1117                if (list_type != db_c_interface_list)
1118                    *status = ept_s_invalid_context;
1119                break;
1120
1121            case rpc_c_ep_match_by_obj:
1122                if (list_type != db_c_object_list)
1123                    *status = ept_s_invalid_context;
1124                break;
1125
1126            default:
1127                *status = rpc_s_invalid_inquiry_type;
1128                break;
1129        }
1130
1131        if (! STATUS_OK(status))
1132        {
1133            db_delete_context(h, entry_handle);
1134            return;
1135        }
1136    }
1137
1138    lookup_match(inquiry_type, object, interface, vers_option, max_ents, num_ents, entries, list_type,
1139        &lp, status);
1140
1141    if (! STATUS_OK(status))
1142    {
1143        /*  Lookup failed so delete
1144         *  the context handle and free
1145         *  the towers that have been allocated
1146         */
1147        db_delete_context(h, entry_handle);
1148
1149        for (i = 0; i < *num_ents; i++)
1150            rpc_ss_free(entries[i].tower);
1151
1152        *num_ents = 0;
1153        return;
1154    }
1155
1156    db_save_context(h, entry_handle, list_type, lp, pass);
1157
1158    if (*num_ents == 0)
1159    {
1160        SET_STATUS(status, ept_s_not_registered);
1161    }
1162}
1163
1164INTERNAL void lookup_match(inquiry_type, object, interface, vers_option, max_ents, num_ents, entries, list_type,
1165    lpp, status)
1166unsigned32          inquiry_type;
1167uuid_p_t            object;
1168rpc_if_id_p_t       interface;
1169unsigned32          vers_option;
1170unsigned32          max_ents;
1171unsigned32          *num_ents;
1172ept_entry_t         entries[];
1173unsigned32          list_type;
1174db_lists_t          **lpp;
1175error_status_t      *status;
1176{
1177    boolean32       match;
1178    db_lists_t      *lp;
1179    db_entry_t      *entp;
1180    error_status_t  tmp_st;
1181
1182    for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp))
1183    {
1184        entp = (db_entry_t *) lp;
1185
1186        if (entp->delete_flag) continue;
1187
1188        match = false;
1189        switch ((int)inquiry_type)
1190        {
1191            case rpc_c_ep_all_elts:
1192                match = true;
1193                break;
1194
1195            case rpc_c_ep_match_by_if:
1196                if (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st))
1197                    match = true;
1198                break;
1199
1200            case rpc_c_ep_match_by_obj:
1201                if (uuid_equal(object, &entp->object, &tmp_st))
1202                    match = true;
1203                break;
1204
1205            case rpc_c_ep_match_by_both:
1206                if (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st) &&
1207                    uuid_equal(object, &entp->object, &tmp_st))
1208                    match = true;
1209                break;
1210
1211            default:
1212                assert(status != NULL);
1213                *status = rpc_s_invalid_inquiry_type;
1214                return;
1215
1216        }
1217
1218        if (match)
1219        {
1220            if ((inquiry_type == rpc_c_ep_match_by_if) || (inquiry_type == rpc_c_ep_match_by_both))
1221            {
1222                /* check interface version
1223                 */
1224
1225                match = false;
1226                switch ((int)vers_option)
1227                {
1228                    case rpc_c_vers_all:
1229                        match = true;
1230                        break;
1231
1232                    case rpc_c_vers_compatible:
1233                        if ((interface->vers_major == entp->interface.vers_major) &&
1234                            (interface->vers_minor <= entp->interface.vers_minor))
1235                            match = true;
1236                        break;
1237
1238                    case rpc_c_vers_exact:
1239                        if ((interface->vers_major == entp->interface.vers_major) &&
1240                            (interface->vers_minor == entp->interface.vers_minor))
1241                            match = true;
1242                        break;
1243
1244                    case rpc_c_vers_major_only:
1245                        if (interface->vers_major == entp->interface.vers_major)
1246                            match = true;
1247                        break;
1248
1249                    case rpc_c_vers_upto:
1250                        if (interface->vers_major > entp->interface.vers_major)
1251                            match = true;
1252                        else
1253                        if ((interface->vers_major == entp->interface.vers_major) &&
1254                            (interface->vers_minor >= entp->interface.vers_minor))
1255                            match = true;
1256                        break;
1257
1258                    default:
1259                        assert(status != NULL);
1260                        *status = rpc_s_invalid_vers_option;
1261                        return;
1262                }
1263            }
1264        }
1265
1266        if (match)
1267        {
1268            if (*num_ents >= max_ents)
1269            {
1270                break;
1271            }
1272
1273            epdb_to_ept(entp, &entries[*num_ents], status);
1274            if (! STATUS_OK(status)) return;
1275
1276            (*num_ents)++;
1277        }
1278    }
1279
1280    *lpp = lp;
1281
1282    SET_STATUS_OK(status);
1283}
1284
1285/*
1286 *  epdb_fwd
1287 *
1288 *  Invoke map or map_mgmt to do a sequence of searches through the
1289 *  endpoint map for appropriate entries to forward to and return pointers
1290 *  to these entries.  Copy the entries' addr info into fwd_addrs.
1291 *
1292 *  map_mgmt is used for the search if the interface is the mgmt interface,
1293 *  otherwise map is used.
1294 *
1295 *  If bad status is returned delete the search context, otherwise map
1296 *  will save it.
1297 *
1298 * NB: caller should set *num_ents to 0 or appropriate offset into fwd_addrs.
1299 *
1300 * Note: we do not forward to an entry with a nil interface id
1301 * AND a nil object id.  If this ever becomes desireable, it will
1302 * likely require visiting (fixing) the protocol service implementations
1303 * that use DG style forwarding.  The implementations may try to forward
1304 * first through the map and only if the forward map fails, then attempt
1305 * to perform normal pkt handling.  The problem is that allowing a tuple
1306 * with a nil interface AND object id to be registered will result in
1307 * an inexact lookup match (due to the nil interface id) for operations
1308 * that are really for the server implementing the endpoint map operations.
1309 *
1310 * Also note that rpcd.c/fwd_map invokes epdb_fwd with max_ents = 1 and
1311 * map_handle = NULL.  We could remove the context handle mgmt code from
1312 * epdb_fwd and gain some in performance - but we'd still need to leave
1313 * the context handle code in map and map_match for epdb_map.
1314 */
1315
1316PRIVATE void epdb_fwd(h_, object, interface, data_rep,
1317                        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor,
1318                        addr, map_handle, max_ents, num_ents, fwd_addrs, status)
1319epdb_handle_t           h_;
1320uuid_p_t                object;
1321rpc_if_id_p_t           interface;
1322rpc_syntax_id_p_t       data_rep;
1323rpc_protocol_id_t       rpc_protocol;
1324unsigned32              rpc_protocol_vers_major;
1325unsigned32              rpc_protocol_vers_minor;
1326rpc_addr_p_t            addr;
1327ept_lookup_handle_t     *map_handle;
1328unsigned32              max_ents;
1329unsigned32              *num_ents;
1330rpc_addr_p_t            fwd_addrs[];
1331unsigned32              *status;
1332{
1333    struct db       *h = (struct db *) h_;
1334    rpc_if_rep_p_t  mgmt_if_rep;
1335    db_entry_t      **db_entries;
1336    unsigned32      start_ent;
1337    unsigned32      i;
1338    error_status_t  tmp_st;
1339
1340    mgmt_if_rep = (rpc_if_rep_p_t) mgmt_v1_0_s_ifspec;
1341
1342    if (db_different_context(h, map_handle, status))
1343        return;
1344
1345    db_entries = (db_entry_t **) malloc(max_ents * sizeof(db_entry_p_t));
1346
1347    /* lock database before delete_context or lookup
1348     */
1349    db_lock(h);
1350
1351    if ((fwd_addrs == NULL) || (db_entries == NULL) || (max_ents == 0) || (*num_ents > max_ents))
1352    {
1353        if (db_entries != NULL) free(db_entries);
1354        db_delete_context(h, map_handle);
1355        SET_STATUS(status, ept_s_cant_perform_op);
1356        db_unlock(h);
1357        return;
1358    }
1359
1360    start_ent = *num_ents;
1361
1362    if (uuid_equal(&interface->uuid, &mgmt_if_rep->id, &tmp_st))
1363        map_mgmt(h, object, data_rep,
1364        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr->rpc_protseq_id,
1365        map_handle, max_ents, num_ents, db_entries, status);
1366    else
1367        map(h, object, interface, data_rep,
1368        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr->rpc_protseq_id,
1369        map_handle, max_ents, num_ents, db_entries, status);
1370    if (! STATUS_OK(status))
1371    {
1372        free(db_entries);
1373        db_unlock(h);
1374        return;
1375    }
1376
1377    for (i = start_ent; i < *num_ents; i++)
1378    {
1379        rpc__naf_addr_copy(db_entries[i]->addr, &fwd_addrs[i], status);
1380        if (! STATUS_OK(status))
1381        {
1382            /*  don't remember context but return
1383             *  addrs that already copied to oput array.
1384             */
1385            db_delete_context(h, map_handle);
1386            *num_ents = i;
1387            if (*num_ents > 0)
1388            {
1389                SET_STATUS_OK(status);
1390            }
1391            else
1392            {
1393                SET_STATUS(status, ept_s_cant_perform_op);
1394            }
1395            break;
1396        }
1397    }
1398
1399    free(db_entries);
1400
1401    db_unlock(h);
1402}
1403
1404/*  epdb_map
1405 *  Invoke map or map_mgmt to do a sequence of searches through the
1406 *  endpoint map for appropriate entries to forward to and return pointers
1407 *  to these entries.  Copy the entries' tower info into fwd_towers.
1408 *
1409 *  map_mgmt is used for the search if the interface is the mgmt interface,
1410 *  otherwise map is used.
1411 *
1412 *  If bad status is returned delete the search context, otherwise map
1413 *  will save it.
1414 *
1415 *  NB: caller should set *num_ents to 0 or appropriate offset into fwd_towers.
1416 */
1417PRIVATE void epdb_map(h_, object, map_tower, map_handle, max_ents, num_ents, fwd_towers, status)
1418epdb_handle_t       h_;
1419uuid_p_t            object;
1420twr_p_t             map_tower;
1421ept_lookup_handle_t *map_handle;
1422unsigned32          max_ents;
1423unsigned32          *num_ents;
1424twr_t               *fwd_towers[];
1425unsigned32          *status;
1426{
1427    struct db       *h = (struct db *) h_;
1428    twr_fields_t    twr_fields, *tfp;
1429    rpc_if_rep_p_t  mgmt_if_rep;
1430    db_entry_t      **db_entries;
1431    unsigned32      start_ent;
1432    unsigned32      i;
1433    error_status_t  tmp_st;
1434
1435    tfp = &twr_fields;
1436    mgmt_if_rep = (rpc_if_rep_p_t) mgmt_v1_0_s_ifspec;
1437
1438    if (db_different_context(h, map_handle, status))
1439        return;
1440
1441    /*  lock database before delete_context or map
1442     */
1443    db_lock(h);
1444
1445    tower_to_fields(map_tower, &twr_fields, status);
1446    if (! STATUS_OK(status))
1447    {
1448        db_delete_context(h, map_handle);
1449        SET_STATUS(status, ept_s_invalid_entry);
1450        db_unlock(h);
1451        return;
1452    }
1453
1454    epdb_chk_map_entry(&twr_fields, status);
1455    if (! STATUS_OK(status))
1456    {
1457        db_delete_context(h, map_handle);
1458        SET_STATUS(status, ept_s_invalid_entry);
1459        db_unlock(h);
1460        return;
1461    }
1462
1463    db_entries = (db_entry_t **) malloc(max_ents * sizeof(db_entry_p_t));
1464
1465    if ((db_entries == NULL) || (fwd_towers == NULL) || (max_ents == 0) || (*num_ents > max_ents))
1466    {
1467        if (db_entries != NULL) free(db_entries);
1468        db_delete_context(h, map_handle);
1469        assert(status != NULL);
1470        SET_STATUS(status, ept_s_cant_perform_op);
1471        db_unlock(h);
1472        return;
1473    }
1474
1475    start_ent = *num_ents;
1476
1477    if (uuid_equal(&tfp->interface.uuid, &mgmt_if_rep->id, &tmp_st))
1478        map_mgmt(h, object, &tfp->data_rep,
1479        tfp->rpc_protocol, tfp->rpc_protocol_vers_major, tfp->rpc_protocol_vers_minor,
1480        tfp->protseq, map_handle, max_ents, num_ents, db_entries, status);
1481    else
1482        map(h, object, &tfp->interface, &tfp->data_rep,
1483        tfp->rpc_protocol, tfp->rpc_protocol_vers_major, tfp->rpc_protocol_vers_minor,
1484        tfp->protseq, map_handle, max_ents, num_ents, db_entries, status);
1485    if (! STATUS_OK(status))
1486    {
1487        free(db_entries);
1488        db_unlock(h);
1489        return;
1490    }
1491
1492    for (i = start_ent; i < *num_ents; i++)
1493    {
1494        tower_ss_copy(&(db_entries[i]->tower), &fwd_towers[i], status);
1495        if (! STATUS_OK(status))
1496        {
1497            /*  don't remember context but return
1498             *  towers that already copied to oput array.
1499             */
1500            db_delete_context(h, map_handle);
1501            *num_ents = i;
1502            if (*num_ents > 0)
1503            {
1504                SET_STATUS_OK(status);
1505            }
1506            else
1507            {
1508                SET_STATUS(status, ept_s_cant_perform_op);
1509            }
1510            break;
1511        }
1512    }
1513
1514    free(db_entries);
1515
1516    db_unlock(h);
1517}
1518
1519/*
1520 *  Search the endpoint database looking for entries which match the target object,
1521 *  interface, etc.
1522 *
1523 *  If the target object is non-nil, do a 2 pass search
1524 *  First, search the objectq looking for exact object/interface matches.
1525 *  Second, search the interfaceq for interface match/object nil
1526 *
1527 *  If the target object is nil
1528 *  Search the interfaceq for interface match/object nil (same as pass 2 above)
1529 *
1530 *  The following table gives some examples of applying the above algorithm
1531 *  to various map entrys (the table assumes that the entrys already exactly
1532 *  match the data rep, protseq, versions, etc. specified in the key):
1533 *
1534 *  Keys and entrys of the form:    <object,interface>
1535 *  Matches (in order of specificity):
1536 *          Moi     - Match on Object and Interface
1537 *          Mi      - Match on Interface
1538 *  No Match:  ' - '
1539 *
1540 *
1541 *   \   Map   |
1542 *     \ entry |
1543 *  key  \     | <nil,I1> <nil,I2> <O1,I1> <O1,I2> <O2,I1>
1544 *  -----------|-------------------------------------------
1545 *  <nil,I1>   |   Moi       -        -       -      -
1546 *  <O1,I1>    |   Mi        -       Moi      -      -
1547 *
1548 */
1549
1550INTERNAL void map(h, object, interface, data_rep,
1551        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1552        map_handle, max_ents, n_ents, db_entries, status)
1553struct db               *h;
1554uuid_p_t                object;
1555rpc_if_id_p_t           interface;
1556rpc_syntax_id_p_t       data_rep;
1557rpc_protocol_id_t       rpc_protocol;
1558unsigned32              rpc_protocol_vers_major;
1559unsigned32              rpc_protocol_vers_minor;
1560rpc_protseq_id_t        protseq;
1561ept_lookup_handle_t     *map_handle;
1562unsigned32              max_ents;
1563unsigned32              *n_ents;
1564db_entry_t              *db_entries[];
1565unsigned32              *status;
1566{
1567    unsigned32      pass;
1568    db_list_type_t  list_type;
1569    db_lists_t      *lp;
1570    error_status_t  tmp_st;
1571
1572    SET_STATUS_OK(status);
1573
1574    if ((map_handle == NULL) || (*map_handle == NULL))
1575    {
1576        if (uuid_is_nil(object, &tmp_st))
1577        {
1578            pass = 2;
1579            list_type = db_c_interface_list;
1580            lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid);
1581        }
1582        else
1583        {
1584            pass = 1;
1585            list_type = db_c_object_list;
1586            lp = db_list_first(&h->lists_mgmt, list_type, object);
1587        }
1588    }
1589    else
1590    {
1591        db_get_context(h, map_handle, &list_type, &lp, &pass, status);
1592        if (! STATUS_OK(status)) return;
1593    }
1594
1595    /*  search objectq for object/interface match */
1596    if (pass == 1)
1597    {
1598        map_match(
1599            object, interface, data_rep,
1600            rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1601            max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status);
1602        if (! STATUS_OK(status))
1603        {
1604            db_delete_context(h, map_handle);
1605            return;
1606        }
1607
1608        if ((*n_ents >= max_ents) && ((lp != NULL) || (map_handle == NULL)))
1609        {
1610            /*  If entry buffer is full and
1611             *  have found next match or are not saving context
1612             *  save context and return
1613             *  (save_context just returns if map_handle == NULL)
1614             */
1615            db_save_context(h, map_handle, list_type, lp, pass);
1616            return;
1617        }
1618
1619        /*  get organized for next pass
1620         */
1621        pass = 2;
1622        list_type = db_c_interface_list;
1623        lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid);
1624
1625    }   /* end of pass 1 */
1626
1627    /*  search interfaceq for interface match/object nil */
1628    if (pass == 2)
1629    {
1630        map_match(
1631            &nil_uuid, interface, data_rep,
1632            rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1633            max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status);
1634        if (! STATUS_OK(status))
1635        {
1636            db_delete_context(h, map_handle);
1637            return;
1638        }
1639    }
1640
1641    /*  If there's context to be saved, save it.
1642     *  If there's no context to save, free entry_handle's
1643     *  context and set entry_handle to NULL
1644     */
1645    db_save_context(h, map_handle, list_type, lp, pass);
1646
1647    if (*n_ents == 0)
1648    {
1649        SET_STATUS(status, ept_s_not_registered);
1650    }
1651}
1652
1653INTERNAL void map_match(
1654        object, interface, data_rep,
1655        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1656        max_ents, n_ents, entries, map_handle, pass, list_type, lpp, status)
1657uuid_p_t                object;
1658rpc_if_id_p_t           interface;
1659rpc_syntax_id_p_t       data_rep;
1660rpc_protocol_id_t       rpc_protocol;
1661unsigned32              rpc_protocol_vers_major;
1662unsigned32              rpc_protocol_vers_minor ATTRIBUTE_UNUSED;
1663rpc_protseq_id_t        protseq;
1664unsigned32              max_ents;
1665unsigned32              *n_ents;
1666db_entry_t              *entries[];
1667ept_lookup_handle_t     *map_handle;
1668unsigned32              pass ATTRIBUTE_UNUSED;
1669db_list_type_t          list_type;
1670db_lists_t              **lpp;
1671unsigned32              *status;
1672{
1673    boolean32       object_nil;
1674    unsigned32      data_rep_vers_major,
1675                    data_rep_vers_minor;
1676    unsigned32      tmp_st;
1677    db_lists_t      *lp;
1678    db_entry_t      *entp;
1679
1680    SET_STATUS_OK(status);
1681
1682    object_nil = uuid_is_nil(object, &tmp_st);
1683    data_rep_vers_major = RPC_IF_VERS_MAJOR(data_rep->version);
1684    data_rep_vers_minor = RPC_IF_VERS_MINOR(data_rep->version);
1685
1686    for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp))
1687    {
1688        entp = (db_entry_t *) lp;
1689
1690        if (entp->delete_flag) continue;
1691
1692        if  (((object_nil && entp->object_nil) ||
1693                uuid_equal(object, &entp->object, &tmp_st)) &&
1694            uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st) &&
1695            (interface->vers_major == entp->interface.vers_major) &&
1696            (interface->vers_minor <= entp->interface.vers_minor) &&
1697            (protseq == entp->addr->rpc_protseq_id) &&
1698            uuid_equal(&data_rep->id, &entp->data_rep_id, &tmp_st) &&
1699            (data_rep_vers_major == entp->data_rep_vers_major) &&
1700            (data_rep_vers_minor <= entp->data_rep_vers_minor) &&
1701            (rpc_protocol == entp->rpc_protocol) &&
1702            (rpc_protocol_vers_major == entp->rpc_protocol_vers_major))
1703            /*
1704             * We dont do this so we can rev the minor protocol number
1705             * && (rpc_protocol_vers_minor <= entp->rpc_protocol_vers_minor) )
1706             */
1707        {
1708            /*
1709             *  found the next match and have filled the
1710             *  entries vector so quit search
1711             */
1712            if (*n_ents >= max_ents)
1713            {
1714                *lpp = lp;
1715                return;
1716            }
1717
1718            entries[*n_ents] = entp;
1719
1720            (*n_ents)++;
1721
1722            /* if not saving search context don't look for next matching
1723             * entry
1724             */
1725            if ((map_handle == NULL) && (*n_ents >= max_ents))
1726            {
1727                *lpp = lp;
1728                return;
1729            }
1730        } /* entry == target */
1731
1732    } /* for lp */
1733
1734    *lpp = lp;
1735}
1736
1737/*  map_mgmt
1738 *  Packet is for the mgmt interface which all processes export.
1739 *  Look for entries with matching object, protseq, data_rep,
1740 *  and rpc_protocol.  Only return one entry per endpoint.
1741 */
1742INTERNAL void map_mgmt(h, object, data_rep,
1743        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1744        map_handle, max_ents, n_ents, db_entries, status)
1745struct db               *h;
1746uuid_p_t                object;
1747rpc_syntax_id_p_t       data_rep;
1748rpc_protocol_id_t       rpc_protocol;
1749unsigned32              rpc_protocol_vers_major;
1750unsigned32              rpc_protocol_vers_minor;
1751rpc_protseq_id_t        protseq;
1752ept_lookup_handle_t     *map_handle;
1753unsigned32              max_ents;
1754unsigned32              *n_ents;
1755db_entry_t              *db_entries[];
1756unsigned32              *status;
1757{
1758    unsigned32      pass;
1759    db_list_type_t  list_type;
1760    db_lists_t      *lp;
1761    error_status_t  tmp_st;
1762
1763    if (uuid_is_nil(object, &tmp_st))
1764    {
1765        db_delete_context(h, map_handle);
1766        SET_STATUS(status, ept_s_invalid_entry);
1767        return;
1768    }
1769
1770    if ((map_handle == NULL) || (*map_handle == NULL))
1771    {
1772        pass = 1;
1773        list_type = db_c_object_list;
1774        lp = db_list_first(&h->lists_mgmt, list_type, object);
1775    }
1776    else
1777    {
1778        db_get_context(h, map_handle, &list_type, &lp, &pass, status);
1779        if (! STATUS_OK(status)) return;
1780    }
1781
1782    map_mgmt_match(
1783        object, data_rep,
1784        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1785        max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status);
1786    if (! STATUS_OK(status))
1787    {
1788        db_delete_context(h, map_handle);
1789        return;
1790    }
1791
1792    /*  If there's context to be saved, save it.
1793     *  If there's no context to save, free map_handle's
1794     *  context and set map_handle to NULL
1795     */
1796    db_save_context(h, map_handle, list_type, lp, pass);
1797
1798    if (*n_ents == 0)
1799    {
1800        assert(status != NULL);
1801        SET_STATUS(status, ept_s_not_registered);
1802    }
1803}
1804
1805INTERNAL void map_mgmt_match(
1806        object, data_rep,
1807        rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq,
1808        max_ents, n_ents, entries, map_handle, pass, list_type, lpp, status)
1809uuid_p_t                object;
1810rpc_syntax_id_p_t       data_rep;
1811rpc_protocol_id_t       rpc_protocol;
1812unsigned32              rpc_protocol_vers_major;
1813unsigned32              rpc_protocol_vers_minor ATTRIBUTE_UNUSED;
1814rpc_protseq_id_t        protseq;
1815unsigned32              max_ents;
1816unsigned32              *n_ents;
1817db_entry_t              *entries[];
1818ept_lookup_handle_t     *map_handle;
1819unsigned32              pass ATTRIBUTE_UNUSED;
1820db_list_type_t          list_type;
1821db_lists_t              **lpp;
1822unsigned32              *status;
1823{
1824    unsigned32      data_rep_vers_major,
1825                    data_rep_vers_minor;
1826    unsigned32      tmp_st;
1827    db_lists_t      *lp;
1828    db_entry_t      *entp;
1829
1830    SET_STATUS_OK(status);
1831
1832    data_rep_vers_major = RPC_IF_VERS_MAJOR(data_rep->version);
1833    data_rep_vers_minor = RPC_IF_VERS_MINOR(data_rep->version);
1834
1835    for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp))
1836    {
1837        entp = (db_entry_t *) lp;
1838
1839        if (entp->delete_flag) continue;
1840
1841        if (uuid_equal(object, &entp->object, &tmp_st) &&
1842            (protseq == entp->addr->rpc_protseq_id) &&
1843            uuid_equal(&data_rep->id, &entp->data_rep_id, &tmp_st) &&
1844            (data_rep_vers_major == entp->data_rep_vers_major) &&
1845            (data_rep_vers_minor <= entp->data_rep_vers_minor) &&
1846            (rpc_protocol == entp->rpc_protocol) &&
1847            (rpc_protocol_vers_major == entp->rpc_protocol_vers_major) &&
1848            /*
1849             * We dont do this so we can rev the minor protocol number
1850             * (rpc_protocol_vers_minor <= entp->rpc_protocol_vers_minor) &&
1851             */
1852            /*  match - see whether already returning
1853             *  this endpoint in entries
1854             */
1855            map_mgmt_endpt_unique(entp->addr, *n_ents, entries) )
1856        {
1857            /*
1858             *  found the next match with unique endpoint
1859             */
1860
1861            /*
1862             *  have filled the entries vector so quit search
1863             */
1864            if (*n_ents >= max_ents)
1865            {
1866                *lpp = lp;
1867                return;
1868            }
1869
1870            entries[*n_ents] = entp;
1871
1872            (*n_ents)++;
1873
1874            /* if not saving search context don't look for next matching
1875             * entry
1876             */
1877            if ((map_handle == NULL) && (*n_ents >= max_ents))
1878            {
1879                *lpp = lp;
1880                return;
1881            }
1882        } /* entry == target */
1883
1884    } /* for lp */
1885
1886    *lpp = lp;
1887}
1888
1889/*  map_mgmt_endpt_unique
1890 *  return true if addr does not match addr of any entry in entries
1891 *  otherwise return false
1892 */
1893INTERNAL boolean32 map_mgmt_endpt_unique(addr, n_ents, entries)
1894rpc_addr_p_t    addr;
1895unsigned32      n_ents;
1896db_entry_t      *entries[];
1897{
1898    unsigned32      i;
1899    error_status_t  tmp_st;
1900
1901    for (i = 0; i < n_ents; i++)
1902    {
1903        /*  matching endpoint
1904         */
1905        if (rpc__naf_addr_compare(addr, entries[i]->addr, &tmp_st))
1906            return(false);
1907    }
1908
1909    /*  no matching endpoint found
1910     */
1911    return(true);
1912}
1913
1914
1915/*
1916 * Return the database object's id.
1917 */
1918PRIVATE void epdb_inq_object(h_, object, status)
1919epdb_handle_t h_;
1920idl_uuid_t *object;
1921error_status_t *status;
1922{
1923    struct db *h = (struct db *) h_;
1924
1925    SET_STATUS_OK(status);
1926
1927    *object = h->object;
1928}
1929
1930PRIVATE void epdb_delete_lookup_handle(h_, entry_handle)
1931epdb_handle_t       h_;
1932ept_lookup_handle_t *entry_handle;
1933{
1934    struct db *h = (struct db *) h_;
1935
1936    db_lock(h);
1937
1938    db_delete_context(h, entry_handle);
1939
1940    db_unlock(h);
1941}
1942