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**      rpcdep.c
82**
83**  FACILITY:
84**
85**      RPC Daemon
86**
87**  ABSTRACT:
88**
89**  The DCE 1.0 Endpoint Map (ep_) Manager.
90**
91**
92*/
93
94#include <commonp.h>
95#include <com.h>
96#include <dce/ep.h>
97
98#include <rpcdp.h>
99#include <rpcdepdb.h>
100
101#ifdef RPC_LLB
102#include <dce/glb.h>
103#include <rpcdlbdb.h>
104#endif
105
106#include <twrp.h>
107
108/* ====================================================================== */
109/*
110 * DCE 1.0 ept_ manager routines.
111 */
112
113GLOBAL ept_v3_0_epv_t ept_v3_0_mgr_epv =
114{
115    ept_insert,
116    ept_delete,
117    ept_lookup,
118    ept_map,
119    ept_lookup_handle_free,
120    ept_inq_object,
121    ept_mgmt_delete
122};
123
124/*
125 * If REMOTE_ENDPOINT_ACCESS is defined, this will preserve the
126 * pre 1.0.3 semantics (and gaping security hole) which allows
127 * an unauthenticated user to modify (or delete) the endpoint
128 * map on a remote host.
129 */
130
131#ifndef REMOTE_ENDPOINT_ACCESS
132
133INTERNAL int is_unpriv_handle( handle_t h, error_status_t *st )
134{
135
136    error_status_t status,status1;
137    rpc_binding_vector_p_t bv;
138    handle_t binding;
139    unsigned_char_p_t stb,our_netaddr,client_netaddr;
140    unsigned32 i;
141    static unsigned_char_p_t *local_netaddr = NULL;
142    static unsigned32 addr_count = 0;
143    unsigned32 prot_seq = 0;
144    rpc_transport_info_handle_t info;
145    unsigned32 uid = (unsigned32) -1;
146    unsigned32 gid = (unsigned32) -1;
147
148    rpc_binding_inq_prot_seq(h, &prot_seq, &status);
149
150    if (! STATUS_OK(&status))
151    {
152        *st = status;
153        return(1);
154    }
155
156    if (prot_seq == rpc_c_protseq_id_ncalrpc)
157    {
158        rpc_binding_inq_transport_info(h, &info, &status);
159
160        if (! STATUS_OK(&status))
161        {
162            *st = status;
163            return(1);
164        }
165
166        rpc_lrpc_transport_info_inq_peer_eid(info, &uid, &gid);
167
168        *st = rpc_s_ok;
169
170        return (uid != 0);
171    }
172
173/* Get client network address from binding handle (client_netaddr) */
174
175    rpc_binding_server_from_client(h,&binding,&status);
176    if (! STATUS_OK(&status))
177    {
178        *st = status;
179        return(1);
180    }
181    rpc_binding_to_string_binding(binding,&stb,&status);
182
183    if (! STATUS_OK(&status))
184    {
185        rpc_binding_free(&binding,&status1);
186        *st = status;
187        return(1);
188    }
189    rpc_binding_free(&binding,&status1);
190
191    rpc_string_binding_parse(stb,NULL,NULL,&client_netaddr,NULL,NULL,&status);
192    if (! STATUS_OK(&status))
193    {
194        rpc_string_free(&stb,&status1);
195        *st = status;
196        return(1);
197    }
198    rpc_string_free(&stb,&status1);
199
200    /*
201     * Lookup all of the addresses which this node answers to.
202     * Cache these in static storage so we only do this work once.
203     */
204    if (addr_count == 0)
205    {
206        rpc_server_inq_bindings(&bv,&status);
207        if (! STATUS_OK(&status))
208        {
209            rpc_string_free(&client_netaddr,&status1);
210            *st = status;
211            return(1);
212        }
213
214        addr_count = bv->count;
215        local_netaddr = (unsigned_char_p_t *) malloc(
216                        (size_t) (addr_count * sizeof(unsigned_char_p_t)));
217        if (local_netaddr == NULL)
218        {
219            rpc_string_free(&client_netaddr,&status1);
220            rpc_binding_vector_free(&bv,&status1);
221            *st = ept_s_no_memory;
222            return(1);
223        }
224
225        for ( i=0; i < bv->count; i++ )
226        {
227            rpc_binding_to_string_binding(bv->binding_h[i],&stb,&status);
228            if (! STATUS_OK(&status))
229            {
230                rpc_binding_vector_free(&bv,&status1);
231                rpc_string_free(&client_netaddr,&status1);
232                *st = status;
233                return(1);
234            }
235            rpc_string_binding_parse(stb,NULL,NULL,
236                                     &our_netaddr,NULL,NULL,&status);
237            if (! STATUS_OK(&status))
238            {
239                rpc_binding_vector_free(&bv,&status1);
240                rpc_string_free(&stb,&status1);
241                rpc_string_free(&client_netaddr,&status1);
242                *st = status;
243                return(1);
244            }
245
246            local_netaddr[i] = our_netaddr;
247            rpc_string_free(&stb,&status1);
248        }
249        rpc_binding_vector_free(&bv,&status1);
250    }
251
252    /*
253     * Compare the addresses with the client address
254     */
255    *st = rpc_s_ok;
256    for ( i=0; i < addr_count; i++ )
257    {
258        if(strcmp((char*) client_netaddr, (char*) local_netaddr[i]) == 0)
259        {
260            rpc_string_free(&client_netaddr,&status1);
261            return(0);
262        }
263    }
264    rpc_string_free(&client_netaddr,&status1);
265    return(1);
266
267}
268
269#endif /* notdef REMOTE_ENDPOINT_ACCESS */
270
271/*
272 * Check whether endpoint is a named pipe
273 */
274PRIVATE boolean ept__is_ncacn_np(
275	ept_entry_p_t       entry)
276{
277    unsigned16 floor_count, count;
278    byte_p_t tower = entry->tower->tower_octet_string;
279
280    if (entry->tower->tower_length < TWR_C_TOWER_FLR_COUNT_SIZE)
281    {
282        return false; /* hopefully someone else will pick this up */
283    }
284
285    memcpy((char *)&floor_count, tower, TWR_C_TOWER_FLR_COUNT_SIZE);
286    RPC_RESOLVE_ENDIAN_INT16 (floor_count);
287
288    tower += TWR_C_TOWER_FLR_COUNT_SIZE;
289
290    for ( count = 0; count < floor_count; count++ )
291    {
292        unsigned16 id_size, addr_size;
293        unsigned8 id;
294
295        if (TWR_C_TOWER_FLR_LHS_COUNT_SIZE >
296            entry->tower->tower_length - (tower - entry->tower->tower_octet_string))
297        {
298            return false;
299        }
300        memcpy ((char *)&id_size, tower, TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
301        RPC_RESOLVE_ENDIAN_INT16 (id_size);
302
303        if (id_size == TWR_C_TOWER_PROT_ID_SIZE)
304        {
305            if ((unsigned) (TWR_C_TOWER_FLR_LHS_COUNT_SIZE + TWR_C_TOWER_PROT_ID_SIZE) >
306                entry->tower->tower_length - (tower - entry->tower->tower_octet_string))
307            {
308                return false;
309            }
310            memcpy ((char *)&id, (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE),
311                    TWR_C_TOWER_PROT_ID_SIZE);
312
313            if (id == TWR_C_FLR_PROT_ID_NP)
314            {
315                return true;
316            }
317        }
318
319        /* skip this floor */
320        if ((unsigned) (TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size + TWR_C_TOWER_FLR_RHS_COUNT_SIZE) >
321            entry->tower->tower_length - (tower - entry->tower->tower_octet_string))
322        {
323            return false;
324        }
325        memcpy ((char *)&addr_size, (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE +
326                                    id_size), TWR_C_TOWER_FLR_RHS_COUNT_SIZE);
327        RPC_RESOLVE_ENDIAN_INT16 (addr_size);
328
329        if ((unsigned) ((TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size +
330                        TWR_C_TOWER_FLR_RHS_COUNT_SIZE + addr_size)) >
331            (entry->tower->tower_length - (tower - entry->tower->tower_octet_string)))
332        {
333            return false;
334        }
335        tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size +
336                 TWR_C_TOWER_FLR_RHS_COUNT_SIZE + addr_size;
337    }
338
339    return false;
340}
341
342PRIVATE void ept_insert(
343	handle_t            h,
344	unsigned32          num_ents,
345	ept_entry_t         entries[],
346	boolean32           replace,
347	error_status_t      *status)
348{
349    epdb_handle_t   epdb;
350    ept_entry_t     *entp;
351    unsigned32             i;
352    error_status_t  tmp_st;
353
354    epdb_handle_from_ohandle(h, &epdb, status);
355    if (! STATUS_OK(status))
356        return;
357
358#ifndef REMOTE_ENDPOINT_ACCESS
359    if ( is_unpriv_handle(h,&tmp_st) )
360    {
361        assert(status != NULL);
362        *status = ept_s_cant_perform_op;
363        return;
364    }
365#endif /* notdef REMOTE_ENDPOINT_ACCESS */
366
367    for (i = 0, entp = &entries[0]; i < num_ents; i++, entp++)
368    {
369        /*
370         * Don't insert named pipe endpoints for the moment - there is
371         * no client side code to support them.
372         */
373        if (ept__is_ncacn_np(entp))
374        {
375            /* skip */
376            continue;
377        }
378
379        epdb_insert(epdb, entp, replace, status);
380        if (! STATUS_OK(status))
381        {
382            if (dflag)
383                show_st("ept_insert  Unable to update endpoint database", status);
384
385            ept_delete(h, i, entries, &tmp_st);
386            return;
387        }
388    }
389}
390
391PRIVATE void ept_delete(
392	handle_t            h,
393	unsigned32          num_ents,
394	ept_entry_t         entries[],
395	error_status_t      *status)
396
397{
398    epdb_handle_t   epdb;
399    ept_entry_t     *entp;
400    unsigned32             i;
401    error_status_t  tmp_st;
402
403    epdb_handle_from_ohandle(h, &epdb, status);
404    if (! STATUS_OK(status))
405        return;
406
407#ifndef REMOTE_ENDPOINT_ACCESS
408    if ( is_unpriv_handle(h,&tmp_st) )
409    {
410        assert(status != NULL);
411        *status = ept_s_cant_perform_op;
412        return;
413    }
414#endif /* notdef REMOTE_ENDPOINT_ACCESS */
415
416    for (i = 0, entp = &entries[0]; i < num_ents; i++, entp++)
417    {
418        epdb_delete(epdb, entp, status);
419        if (! STATUS_OK(status))
420        {
421            if (dflag)
422                show_st("ept_delete  Unable to update endpoint database", status);
423            return;
424        }
425    }
426}
427
428PRIVATE void ept_lookup(
429	handle_t            h,
430	unsigned32          inquiry_type,
431	uuid_p_t            object,
432	rpc_if_id_p_t       interface,
433	unsigned32          vers_option,
434	ept_lookup_handle_t *entry_handle,
435	unsigned32          max_ents,
436	unsigned32          *num_ents,
437	ept_entry_t         entries[],
438	error_status_t      *status)
439{
440    epdb_handle_t epdb;
441
442    *num_ents = 0;
443
444    epdb_handle_from_ohandle(h, &epdb, status);
445    if (! STATUS_OK(status))
446        return;
447
448    epdb_lookup(epdb, inquiry_type, object, interface, vers_option, entry_handle,
449               max_ents, num_ents, entries, status);
450
451    if (dflag)
452        printf("ept_lookup  entry_handle %p  *entry_handle %p  *num_ents %lu\n",
453               entry_handle, *entry_handle, (unsigned long) *num_ents);
454}
455
456PRIVATE void ept_map(
457	handle_t            h,
458	uuid_p_t            object,
459	twr_p_t             map_tower,
460	ept_lookup_handle_t *entry_handle,
461	unsigned32          max_towers,
462	unsigned32          *num_towers,
463	twr_t               *towers[],
464	error_status_t      *status)
465{
466    epdb_handle_t epdb;
467
468    *num_towers = 0;
469
470    epdb_handle_from_ohandle(h, &epdb, status);
471    if (! STATUS_OK(status))
472        return;
473
474    epdb_map(epdb, object, map_tower, entry_handle,
475               max_towers, num_towers, towers, status);
476
477#ifdef RPC_LLB
478    if ((*status == ept_s_not_registered) ||
479        (*status == ept_s_invalid_context) ||
480    /*
481     * If finished with ept dbase, search llb dbase
482     */
483        ((*status == rpc_s_ok) &&
484         ((*num_towers < max_towers) ||
485          ((entry_handle != NULL) && (*entry_handle == NULL)) )) )
486    {
487        h = lbdb_inq_handle();
488        lbdb_map(h, object, map_tower, entry_handle,
489               max_towers, num_towers, towers, status);
490
491    }
492#endif
493
494    if (dflag)
495        printf("ept_map  entry_handle %p  *entry_handle %p  *num_towers %lu\n",
496               entry_handle, *entry_handle, (unsigned long) *num_towers);
497}
498
499PRIVATE void ept_lookup_handle_free(
500	handle_t            h ATTRIBUTE_UNUSED,
501	ept_lookup_handle_t *entry_handle,
502	error_status_t      *status)
503{
504    epdb_handle_t epdb;
505
506    epdb = epdb_inq_handle();
507    epdb_delete_lookup_handle(epdb, entry_handle);
508
509    SET_STATUS_OK(status);
510}
511
512PRIVATE void ept_inq_object(
513	handle_t            h,
514	idl_uuid_t          *object,
515	error_status_t      *status)
516{
517    epdb_handle_t epdb;
518
519    epdb_handle_from_ohandle(h, &epdb, status);
520    if (! STATUS_OK(status))
521        return;
522
523    epdb_inq_object(epdb, object, status);
524}
525
526PRIVATE void ept_mgmt_delete(
527	handle_t            h,
528	boolean32           object_speced,
529	uuid_p_t            object,
530	twr_p_t             tower,
531	error_status_t      *status)
532{
533    epdb_handle_t epdb;
534    error_status_t tmp_st;
535
536    epdb_handle_from_ohandle(h, &epdb, status);
537    if (! STATUS_OK(status))
538        return;
539
540#ifndef REMOTE_ENDPOINT_ACCESS
541    if ( is_unpriv_handle(h,&tmp_st) )
542    {
543        assert(status != NULL);
544        *status = ept_s_cant_perform_op;
545        return;
546    }
547#endif /* notdef REMOTE_ENDPOINT_ACCESS */
548
549    epdb_mgmt_delete(epdb, object_speced, object, tower, status);
550}
551
552PRIVATE void ept_lookup_handle_t_rundown(
553	ept_lookup_handle_t entry_handle)
554{
555    epdb_handle_t epdb;
556
557    epdb = epdb_inq_handle();
558    epdb_delete_lookup_handle(epdb,  &entry_handle);
559}
560