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**      comsoc.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Veneer over the BSD socket abstraction not provided by the old sock_
90**  or new rpc_{tower,addr}_ components.
91**
92**
93*/
94
95#include <config.h>
96#include <dce/lrpc.h>
97#include <commonp.h>
98#include <com.h>
99#include <comprot.h>
100#include <comnaf.h>
101#include <comp.h>
102#include <comsoc_bsd.h>
103#include <fcntl.h>
104#include <sys/un.h>
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <sys/param.h>
108#include <sys/socket.h>
109#include <cnp.h>
110
111#if HAVE_LW_BASE_H
112#include <lw/base.h>
113#endif
114
115#if HAVE_LWMAPSECURITY_LWMAPSECURITY_H
116#include <lwmapsecurity/lwmapsecurity.h>
117#endif
118
119/* Bizarre hack for HP-UX ia64 where a system header
120 * makes reference to a kernel-only data structure
121 */
122#if defined(__hpux) && defined(__ia64)
123union mpinfou {};
124#endif
125#include <net/if.h>
126#include <sys/ioctl.h>
127/* Hack to ensure we actually get a definition of ioctl on AIX */
128#if defined(_AIX) && defined(_BSD)
129int ioctl(int d, int request, ...);
130#endif
131#include <unistd.h>
132#ifdef HAVE_SYS_SOCKIO_H
133#include <sys/sockio.h> /* Not just Linux */
134#endif
135
136/*#include <dce/cma_ux_wrappers.h>*/
137
138/* ======================================================================== */
139
140/*
141 * What we think a socket's buffering is in case rpc__socket_set_bufs()
142 * fails miserably.  The #ifndef is here so that these values can be
143 * overridden in a per-system file.
144 */
145
146#ifndef RPC_C_SOCKET_GUESSED_RCVBUF
147#  define RPC_C_SOCKET_GUESSED_RCVBUF    (4 * 1024)
148#endif
149
150#ifndef RPC_C_SOCKET_GUESSED_SNDBUF
151#  define RPC_C_SOCKET_GUESSED_SNDBUF    (4 * 1024)
152#endif
153
154/*
155 * Maximum send and receive buffer sizes.  The #ifndef is here so that
156 * these values can be overridden in a per-system file.
157 */
158
159#ifndef RPC_C_SOCKET_MAX_RCVBUF
160#  define RPC_C_SOCKET_MAX_RCVBUF (64 * 1024)
161#endif
162
163#ifndef RPC_C_SOCKET_MAX_SNDBUF
164#  define RPC_C_SOCKET_MAX_SNDBUF (64 * 1024)
165#endif
166
167/*
168 * The RPC_SOCKET_DISABLE_CANCEL/RPC_SOCKET_RESTORE_CANCEL macros
169 * are used to disable cancellation before entering library calls
170 * which were non-cancelable under CMA threads but are generally
171 * cancelable on modern POSIX systems.
172 */
173#define RPC_SOCKET_DISABLE_CANCEL	{ int __cs = dcethread_enableinterrupt_throw(0);
174#define RPC_SOCKET_RESTORE_CANCEL	dcethread_enableinterrupt_throw(__cs); }
175
176/*
177 * Macros to paper over the difference between the 4.4bsd and 4.3bsd
178 * socket API.
179 *
180 * The layout of a 4.4 struct sockaddr includes a 1 byte "length" field
181 * which used to be one of the bytes of the "family" field.  (The "family"
182 * field is now 1 byte instead of 2 bytes.)  4.4 provides binary
183 * compatibility with applications compiled with a 4.3 sockaddr definition
184 * by inferring a default length when the supplied length is zero.  Source
185 * compatibility is blown however (if _SOCKADDR_LEN is #define'd) --
186 * applications that assign only to the "family" field will leave the
187 * "length" field possibly non-zero.
188 *
189 * Note that RPC's "sockaddr_t" is always defined to contains only a
190 * family.  (We defined "rpc_addr_t" to be a struct that contains a length
191 * and a sockaddr rather than mucking with the sockaddr itself.)  We
192 * assumed that "sockaddr_t" and "struct sockaddr" are the same.  At
193 * 4.4, this assumption caused problems.  We use RPC_SOCKET_FIX_ADDRLEN
194 * at various opportunities to make sure sockaddrs' length is zero and
195 * that makes the problems go away.
196 *
197 * ADDENDUM:
198 *    This only makes the problem go away on little-endian systems
199 *    where the length field on the 4.4 struct occupies the same position
200 *    as the high byte of the family field on the 4.3 struct.  This is
201 *    no good for i386 FreeBSD, so we have actually adapted sockaddr_t
202 *    to match the system struct sockaddr.
203 *                                           -- Brian Koropoff, Likewise
204 *
205 * RPC_SOCKET_FIX_ADDRLEN takes an "rpc_addr_p_t" (or "rpc_ip_addr_p_t")
206 * as input.  The complicated casting (as opposed to simply setting
207 * ".sa_len" to zero) is to ensure that the right thing happens regardless
208 * of the integer endian-ness of the system).
209 *
210 * RPC_SOCKET_INIT_MGRHDR deals with the differences in the field names of
211 * the "struct msghdr" data type between 4.3 and 4.4.
212 */
213
214#ifdef BSD_4_4_SOCKET
215#define RPC_SOCKET_INIT_MSGHDR(msgp) ( \
216    (msgp)->msg_control         = NULL, \
217    (msgp)->msg_controllen      = 0, \
218    (msgp)->msg_flags           = 0 \
219)
220#else
221#define RPC_SOCKET_INIT_MSGHDR(msgp) ( \
222    (msgp)->msg_accrights       = NULL, \
223    (msgp)->msg_accrightslen    = 0 \
224)
225#endif /* BSD_4_4_SOCKET */
226
227/*#if defined(_SOCKADDR_LEN)
228#define RPC_SOCKET_FIX_ADDRLEN(addrp) ( \
229      ((struct osockaddr *) &(addrp)->sa)->sa_family = \
230              ((struct sockaddr *) &(addrp)->sa)->sa_family \
231  )
232  #else*/
233#define RPC_SOCKET_FIX_ADDRLEN(addrp) do { } while (0)
234/*#endif*/
235
236#ifndef CMSG_ALIGN
237#if defined(_CMSG_DATA_ALIGN)
238#define CMSG_ALIGN _CMSG_DATA_ALIGN
239
240#elif defined(_CMSG_ALIGN)
241#define CMSG_ALIGN _CMSG_ALIGN
242
243#elif defined(__DARWIN_ALIGN32)
244#define CMSG_ALIGN __DARWIN_ALIGN32
245
246#elif defined(ALIGN)
247#define CMSG_ALIGN ALIGN
248#endif
249#endif /* CMSG_ALIGN */
250
251#ifndef CMSG_SPACE
252#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
253#endif
254
255#ifndef CMSG_LEN
256#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
257#endif
258
259/*
260 * BSD socket transport layer info structures
261 */
262typedef struct rpc_bsd_transport_info_s
263{
264    uid_t peer_uid;
265    gid_t peer_gid;
266} rpc_bsd_transport_info_t, *rpc_bsd_transport_info_p_t;
267
268typedef struct rpc_bsd_socket_s
269{
270    int fd;
271    rpc_bsd_transport_info_t info;
272} rpc_bsd_socket_t, *rpc_bsd_socket_p_t;
273
274INTERNAL rpc_socket_error_t
275rpc__bsd_socket_set_default_options (
276                                     rpc_socket_basic_t sockfd)
277{
278#ifdef SO_NOSIGPIPE
279    int on = 1;
280
281    /* Set SO_NOSIGPIPE on the socket */
282    if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on)) == -1) {
283        return errno;
284    }
285#endif
286    return RPC_C_SOCKET_OK;
287}
288
289INTERNAL rpc_socket_error_t rpc__bsd_socket_destruct
290(
291    rpc_socket_t        sock
292);
293
294INTERNAL rpc_socket_error_t rpc__bsd_socket_construct(
295    rpc_socket_t                sock,
296    rpc_protseq_id_t            pseq_id,
297    rpc_transport_info_handle_t info
298);
299
300/* ======================================================================== */
301/*
302 * R P C _ _ S O C K E T _ D U P L I C A T E
303 *
304 * Wrap the native socket representation in a rpc_socket_t. We duplicate the
305 * socket file descriptor because we will eventually end up close(2)ing it.
306 */
307
308INTERNAL rpc_socket_error_t
309rpc__bsd_socket_duplicate(
310    rpc_socket_t        sock,
311    rpc_protseq_id_t    pseq_id ATTRIBUTE_UNUSED,
312    const void *        sockrep /* pointer to native representation */
313    )
314{
315    rpc_socket_error_t  serr;
316    rpc_bsd_socket_p_t  lrpc;
317    const int *         sockfd = (const int *)sockrep;
318
319    if (sockfd == NULL || *sockfd == -1) {
320        return RPC_C_SOCKET_ENOTSOCK;
321    }
322
323    if (sock->pseq_id != pseq_id) {
324        return RPC_C_SOCKET_EINVAL;
325    }
326
327    serr = rpc__bsd_socket_destruct(sock);
328    if (serr != RPC_C_SOCKET_OK) {
329        return serr;
330    }
331
332    serr = rpc__bsd_socket_construct(sock, pseq_id, NULL);
333    if (serr != RPC_C_SOCKET_OK) {
334        return serr;
335    }
336
337    lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
338
339    RPC_SOCKET_DISABLE_CANCEL;
340
341    if (lrpc->fd != -1) {
342        close(lrpc->fd);
343    }
344
345    lrpc->fd = dup(*sockfd);
346
347    serr = ((lrpc->fd == -1) ? errno : RPC_C_SOCKET_OK);
348    if (serr != RPC_C_SOCKET_OK) {
349        goto error;
350    }
351
352    serr = rpc__bsd_socket_set_default_options(lrpc->fd);
353    if (serr != RPC_C_SOCKET_OK) {
354        goto error;
355    }
356
357    RPC_SOCKET_RESTORE_CANCEL;
358
359    return RPC_C_SOCKET_OK;
360
361error:
362    rpc__bsd_socket_destruct(sock);
363    return serr;
364}
365
366/*
367 * R P C _ _ S O C K E T _ C O N S T R U C T
368 *
369 * Create a new socket for the specified Protocol Sequence.
370 * The new socket has blocking IO semantics.
371 *
372 * (see BSD UNIX socket(2)).
373 */
374
375INTERNAL rpc_socket_error_t
376rpc__bsd_socket_construct(
377    rpc_socket_t sock,
378    rpc_protseq_id_t    pseq_id,
379    rpc_transport_info_handle_t info ATTRIBUTE_UNUSED
380    )
381{
382    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
383    rpc_bsd_socket_p_t lrpc = NULL;
384
385    /* set data.point to be 0 in case we get an error
386     and have to call rpc__bsd_socket_destruct */
387    sock->data.pointer = NULL;
388
389    lrpc = calloc(1, sizeof(*lrpc));
390
391    if (!lrpc)
392    {
393        serr = ENOMEM;
394        goto error;
395    }
396
397    sock->data.pointer = (void*) lrpc;
398
399    lrpc->fd            = -1;
400    lrpc->info.peer_uid = -1;
401    lrpc->info.peer_gid = -1;
402
403    RPC_SOCKET_DISABLE_CANCEL;
404    lrpc->fd = socket(
405        (int) RPC_PROTSEQ_INQ_NAF_ID(pseq_id),
406        (int) RPC_PROTSEQ_INQ_NET_IF_ID(pseq_id),
407        0 /*(int) RPC_PROTSEQ_INQ_NET_PROT_ID(pseq_id)*/);
408    serr = ((lrpc->fd == -1) ? errno : RPC_C_SOCKET_OK);
409
410    if (serr == RPC_C_SOCKET_OK) {
411        serr = rpc__bsd_socket_set_default_options(lrpc->fd);
412        if (serr != RPC_C_SOCKET_OK)
413            close (lrpc->fd);
414    }
415    RPC_SOCKET_RESTORE_CANCEL;
416
417    if (serr)
418    {
419        goto error;
420    }
421
422done:
423    return serr;
424
425error:
426    if (lrpc)
427    {
428        rpc__bsd_socket_destruct(sock);
429    }
430
431    goto done;
432}
433
434/*
435 * R P C _ _ S O C K E T _ O P E N _ B A S I C
436 *
437 * A special version of socket_open that is used *only* by
438 * the low level initialization code when it is trying to
439 * determine what network services are supported by the host OS.
440 */
441
442PRIVATE rpc_socket_error_t
443rpc__bsd_socket_open_basic(
444    rpc_naf_id_t        naf,
445    rpc_network_if_id_t net_if,
446    rpc_network_protocol_id_t net_prot ATTRIBUTE_UNUSED,
447    rpc_socket_basic_t        *sock
448    )
449{
450    rpc_socket_error_t  serr;
451
452    /*
453     * Always pass zero as socket protocol to compensate for
454     * overloading the protocol field for named pipes
455     */
456    RPC_SOCKET_DISABLE_CANCEL;
457    *sock = socket((int) naf, (int) net_if, 0);
458    serr = ((*sock == -1) ? errno : RPC_C_SOCKET_OK);
459
460    if (serr == RPC_C_SOCKET_OK) {
461        serr = rpc__bsd_socket_set_default_options(*sock);
462        if (serr != RPC_C_SOCKET_OK)
463            close (*sock);
464    }
465    RPC_SOCKET_RESTORE_CANCEL;
466
467    return serr;
468}
469
470PRIVATE rpc_socket_error_t
471rpc__bsd_socket_close_basic(
472    rpc_socket_basic_t        sock
473    )
474{
475    rpc_socket_error_t  serr;
476
477    RPC_LOG_SOCKET_CLOSE_NTR;
478    RPC_SOCKET_DISABLE_CANCEL;
479    serr = (close(sock) == -1) ? errno : RPC_C_SOCKET_OK;
480    RPC_SOCKET_RESTORE_CANCEL;
481    RPC_LOG_SOCKET_CLOSE_XIT;
482
483    return (serr);
484}
485
486
487/*
488 * R P C _ _ S O C K E T _ C L O S E
489 *
490 * Close (destroy) a socket.
491 *
492 * (see BSD UNIX close(2)).
493 */
494
495INTERNAL rpc_socket_error_t rpc__bsd_socket_destruct
496(
497    rpc_socket_t        sock
498)
499{
500    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
501    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
502
503    if (lrpc && lrpc->fd > 0)
504    {
505
506        RPC_LOG_SOCKET_CLOSE_NTR;
507        RPC_SOCKET_DISABLE_CANCEL;
508        serr = (close(lrpc->fd) == -1) ? errno : RPC_C_SOCKET_OK;
509        RPC_SOCKET_RESTORE_CANCEL;
510        RPC_LOG_SOCKET_CLOSE_XIT;
511    }
512
513    if (lrpc)
514    {
515	free(lrpc);
516        sock->data.pointer = NULL;
517    }
518
519    return serr;
520}
521
522/*
523 * R P C _ _ S O C K E T _ B I N D
524 *
525 * Bind a socket to a specified local address.
526 *
527 * (see BSD UNIX bind(2)).
528 */
529
530INTERNAL rpc_socket_error_t rpc__bsd_socket_bind
531(
532    rpc_socket_t        sock,
533    rpc_addr_p_t        addr
534)
535{
536    rpc_socket_error_t  serr = EINVAL;
537    unsigned32 status;
538    rpc_addr_p_t temp_addr = NULL;
539    boolean has_endpoint = false;
540    int setsock_val = 1;
541    int ncalrpc;
542    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
543
544    RPC_LOG_SOCKET_BIND_NTR;
545
546    ncalrpc = addr->rpc_protseq_id == rpc_c_protseq_id_ncalrpc;
547
548    /*
549     * Check if the address has a well-known endpoint.
550     */
551    if (addr->rpc_protseq_id == rpc_c_protseq_id_ncacn_ip_tcp || ncalrpc)
552    {
553        unsigned_char_t *endpoint;
554
555        rpc__naf_addr_inq_endpoint (addr, &endpoint, &status);
556
557        if (status == rpc_s_ok && endpoint != NULL)
558        {
559            if (endpoint[0] != '\0')    /* test for null string */
560                has_endpoint = true;
561
562            rpc_string_free (&endpoint, &status);
563        }
564        status = rpc_s_ok;
565    }
566
567    /*
568     * If there is no port restriction in this address family, then do a
569     * simple bind.
570     */
571
572    if (! RPC_PROTSEQ_TEST_PORT_RESTRICTION (addr -> rpc_protseq_id))
573    {
574        if (!has_endpoint && ncalrpc)
575        {
576            serr = 0;
577        }
578        else
579        {
580#if defined(SOL_SOCKET) && defined(SO_REUSEADDR)
581	    setsockopt(lrpc->fd, SOL_SOCKET, SO_REUSEADDR,
582		       &setsock_val, sizeof(setsock_val));
583#endif
584            if (addr->sa.family == AF_UNIX && addr->sa.data[0] != '\0')
585            {
586                // This function is going to bind a named socket. First, try
587                // to delete the path incase a previous instance of a program
588                // left it behind.
589                //
590                // Ignore any errors from this function.
591                unlink((const char*)addr->sa.data);
592            }
593            serr =
594                (bind(lrpc->fd, (struct sockaddr *)&addr->sa, addr->len) == -1) ?
595                      errno : RPC_C_SOCKET_OK;
596        }
597    }                                   /* no port restriction */
598
599    else
600    {
601        /*
602         * Port restriction is in place.  If the address has a well-known
603         * endpoint, then do a simple bind.
604         */
605
606        if (has_endpoint)
607        {
608#if defined(SOL_SOCKET) && defined(SO_REUSEADDR)
609	    setsockopt(lrpc->fd, SOL_SOCKET, SO_REUSEADDR,
610		       &setsock_val, sizeof(setsock_val));
611#endif
612            serr = (bind(lrpc->fd, (struct sockaddr *)&addr->sa, addr->len) == -1)?
613                errno : RPC_C_SOCKET_OK;
614        }                               /* well-known endpoint */
615        else
616	{
617
618	    unsigned_char_t *endpoint;
619	    unsigned char c;
620
621	    rpc__naf_addr_inq_endpoint (addr, &endpoint, &status);
622
623	    c = endpoint[0];               /* grab first char */
624	    rpc_string_free (&endpoint, &status);
625
626	    if (c != '\0')       /* test for null string */
627	    {
628	        serr = (bind(lrpc->fd, (struct sockaddr *)&addr->sa, addr->len) == -1)?
629		    errno : RPC_C_SOCKET_OK;
630	    }                               /* well-known endpoint */
631
632	    else
633	    {
634	        /*
635	         * Port restriction is in place and the address doesn't have a
636	         * well-known endpoint.  Try to bind until we hit a good port,
637	         * or exhaust the retry count.
638	         *
639	         * Make a copy of the address to work in; if we hardwire an
640	         * endpoint into our caller's address, later logic could infer
641	         * that it is a well-known endpoint.
642	         */
643
644	        unsigned32 i;
645	        boolean found;
646
647	        for (i = 0, found = false;
648		     (i < RPC_PORT_RESTRICTION_INQ_N_TRIES (addr->rpc_protseq_id))
649		     && !found;
650		     i++)
651	        {
652		    unsigned_char_p_t port_name;
653
654		    rpc__naf_addr_overcopy (addr, &temp_addr, &status);
655
656		    if (status != rpc_s_ok)
657		    {
658		        serr = RPC_C_SOCKET_EIO;
659		        break;
660		    }
661
662		    rpc__naf_get_next_restricted_port (temp_addr -> rpc_protseq_id,
663						   &port_name, &status);
664
665		    if (status != rpc_s_ok)
666		    {
667		        serr = RPC_C_SOCKET_EIO;
668		        break;
669		    }
670
671		    rpc__naf_addr_set_endpoint (port_name, &temp_addr, &status);
672
673		    if (status != rpc_s_ok)
674		    {
675		        serr = RPC_C_SOCKET_EIO;
676		        rpc_string_free (&port_name, &status);
677		        break;
678		    }
679
680		    if (bind(lrpc->fd, (struct sockaddr *)&temp_addr->sa, temp_addr->len) == 0)
681		    {
682		        found = true;
683		        serr = RPC_C_SOCKET_OK;
684		    }
685		    else
686		        serr = RPC_C_SOCKET_EIO;
687
688		    rpc_string_free (&port_name, &status);
689	        }                           /* for i */
690
691	        if (!found)
692	        {
693		    serr = RPC_C_SOCKET_EADDRINUSE;
694	        }
695	    }                               /* no well-known endpoint */
696        }				/* has endpoint */
697    }                                   /* port restriction is in place */
698
699    if (serr == RPC_C_SOCKET_OK && ncalrpc && has_endpoint)
700    {
701	struct sockaddr_un *skun = (struct sockaddr_un *)&addr->sa;
702
703	serr = chmod(skun->sun_path,
704		     S_IRUSR | S_IWUSR | S_IXUSR |
705		     S_IRGRP | S_IWGRP | S_IXGRP |
706		     S_IROTH | S_IWOTH | S_IXOTH) == -1 ? errno : RPC_C_SOCKET_OK;
707    }
708
709    if (temp_addr != NULL)
710        rpc__naf_addr_free (&temp_addr, &status);
711
712    RPC_LOG_SOCKET_BIND_XIT;
713    return (serr);
714}
715
716INTERNAL rpc_socket_error_t rpc__bsd_socket_getpeereid
717(
718    rpc_socket_t        sock,
719    uid_t		*euid,
720    gid_t		*egid
721);
722
723#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
724
725INTERNAL rpc_socket_error_t rpc__bsd_socket_sendpeereid
726(
727    rpc_socket_t        sock,
728    rpc_addr_p_t        addr
729);
730
731INTERNAL rpc_socket_error_t rpc__bsd_socket_recvpeereid
732(
733    rpc_socket_t        sock,
734    uid_t		*euid,
735    gid_t		*egid
736);
737
738#endif
739
740
741/*
742 * R P C _ _ S O C K E T _ C O N N E C T
743 *
744 * Connect a socket to a specified peer's address.
745 * This is used only by Connection oriented Protocol Services.
746 *
747 * (see BSD UNIX connect(2)).
748 */
749
750INTERNAL rpc_socket_error_t rpc__bsd_socket_connect
751(
752    rpc_socket_t        sock,
753    rpc_addr_p_t        addr,
754    rpc_cn_assoc_t      *assoc ATTRIBUTE_UNUSED
755)
756{
757    rpc_socket_error_t  serr;
758    //rpc_binding_rep_t *binding_rep;
759    unsigned_char_t *netaddr, *endpoint;
760    unsigned32      dbg_status;
761    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
762
763    rpc__naf_addr_inq_netaddr (addr,
764                               &netaddr,
765                               &dbg_status);
766    rpc__naf_addr_inq_endpoint (addr,
767                               &endpoint,
768                               &dbg_status);
769
770    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
771        ("CN: connection request initiated to %s[%s]\n",
772         netaddr,
773         endpoint));
774
775connect_again:
776    RPC_LOG_SOCKET_CONNECT_NTR;
777    serr = (connect (
778                (int) lrpc->fd,
779                (struct sockaddr *) (&addr->sa),
780                (int) (addr->len))
781            == -1) ? errno : RPC_C_SOCKET_OK;
782    RPC_LOG_SOCKET_CONNECT_XIT;
783    if (serr == EINTR)
784    {
785        goto connect_again;
786    }
787    else if (serr != RPC_C_SOCKET_OK)
788    {
789        goto error;
790    }
791
792#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
793    serr = rpc__bsd_socket_sendpeereid(sock, addr);
794#endif
795
796cleanup:
797    rpc_string_free (&netaddr, &dbg_status);
798    rpc_string_free (&endpoint, &dbg_status);
799
800    return serr;
801
802error:
803    goto cleanup;
804}
805
806/*
807 * R P C _ _ S O C K E T _ A C C E P T
808 *
809 * Accept a connection on a socket, creating a new socket for the new
810 * connection.  A rpc_addr_t appropriate for the NAF corresponding to
811 * this socket must be provided.  addr.len must set to the actual size
812 * of addr.sa.  This operation fills in addr.sa and sets addr.len to
813 * the new size of the field.  This is used only by Connection oriented
814 * Protocol Services.
815 *
816 * (see BSD UNIX accept(2)).
817 */
818
819INTERNAL rpc_socket_error_t rpc__bsd_socket_accept
820(
821    rpc_socket_t        sock,
822    rpc_addr_p_t        addr,
823    rpc_socket_t        *newsock
824)
825{
826    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
827    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
828    rpc_bsd_socket_p_t newlrpc = NULL;
829    uid_t euid = -1;
830    gid_t egid = -1;
831
832    *newsock = malloc(sizeof (**newsock));
833
834    if (!*newsock)
835    {
836        return ENOMEM;
837    }
838
839    (*newsock)->vtbl = sock->vtbl;
840    (*newsock)->pseq_id = sock->pseq_id;
841
842    newlrpc = malloc(sizeof(*newlrpc));
843    if (!newlrpc)
844    {
845        return ENOMEM;
846    }
847
848    newlrpc->info.peer_uid = -1;
849    newlrpc->info.peer_gid = -1;
850
851    (*newsock)->data.pointer = newlrpc;
852
853accept_again:
854    RPC_LOG_SOCKET_ACCEPT_NTR;
855    if (addr == NULL)
856    {
857        socklen_t addrlen;
858
859        addrlen = 0;
860        newlrpc->fd = accept
861            ((int) lrpc->fd, (struct sockaddr *) NULL, &addrlen);
862    }
863    else
864    {
865        newlrpc->fd = accept
866            ((int) lrpc->fd, (struct sockaddr *) (&addr->sa), (&addr->len));
867    }
868    serr = (newlrpc->fd == -1) ? errno : RPC_C_SOCKET_OK;
869    RPC_LOG_SOCKET_ACCEPT_XIT;
870
871    if (!serr)
872    {
873        serr = rpc__bsd_socket_getpeereid((*newsock), &euid, &egid);
874    }
875    else
876    {
877        goto cleanup;
878    }
879
880    if (serr == EINTR)
881    {
882        goto accept_again;
883    }
884
885    newlrpc->info.peer_uid = euid;
886    newlrpc->info.peer_gid = egid;
887
888cleanup:
889    if (serr && newlrpc)
890    {
891        free(newlrpc);
892    }
893
894    if (serr && *newsock)
895    {
896        free(*newsock);
897    }
898
899    return serr;
900}
901
902/*
903 * R P C _ _ S O C K E T _ L I S T E N
904 *
905 * Listen for a connection on a socket.
906 * This is used only by Connection oriented Protocol Services.
907 *
908 * (see BSD UNIX listen(2)).
909 */
910
911INTERNAL rpc_socket_error_t rpc__bsd_socket_listen
912(
913    rpc_socket_t        sock,
914    int                 backlog
915)
916{
917    rpc_socket_error_t  serr;
918    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
919
920    RPC_LOG_SOCKET_LISTEN_NTR;
921    RPC_SOCKET_DISABLE_CANCEL;
922    serr = (listen(lrpc->fd, backlog) == -1) ? errno : RPC_C_SOCKET_OK;
923    RPC_SOCKET_RESTORE_CANCEL;
924    RPC_LOG_SOCKET_LISTEN_XIT;
925    return (serr);
926}
927
928/*
929 * R P C _ _ S O C K E T _ S E N D M S G
930 *
931 * Send a message over a given socket.  An error code as well as the
932 * actual number of bytes sent are returned.
933 *
934 * (see BSD UNIX sendmsg(2)).
935 */
936
937INTERNAL rpc_socket_error_t rpc__bsd_socket_sendmsg
938(
939    rpc_socket_t        sock,
940    rpc_socket_iovec_p_t iov,       /* array of bufs of data to send */
941    int                 iovcnt,     /* number of bufs */
942    rpc_addr_p_t        addr,       /* addr of receiver */
943    size_t              *cc         /* returned number of bytes actually sent */
944)
945{
946    ssize_t             ret;
947    rpc_socket_error_t  serr;
948    struct msghdr       msg;
949    rpc_bsd_socket_p_t  lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
950
951    *cc = 0;
952
953sendmsg_again:
954
955    memset(&msg, 0, sizeof(msg));
956    RPC_LOG_SOCKET_SENDMSG_NTR;
957    RPC_SOCKET_INIT_MSGHDR(&msg);
958    if ((addr) != NULL)
959    {
960        RPC_SOCKET_FIX_ADDRLEN(addr);
961        msg.msg_name = (caddr_t) &(addr)->sa;
962        msg.msg_namelen = (addr)->len;
963    }
964    else
965    {
966        msg.msg_name = (caddr_t) NULL;
967    }
968    msg.msg_iov = iov;
969    msg.msg_iovlen = iovcnt;
970
971    ret = dcethread_sendmsg (lrpc->fd, &msg, 0);
972    if (ret == (size_t) -1)
973    {
974        serr = errno;
975    }
976    else
977    {
978        serr = RPC_C_SOCKET_OK;
979        *cc = ret;
980    }
981
982    RPC_LOG_SOCKET_SENDMSG_XIT;
983    if (serr == EINTR)
984    {
985        goto sendmsg_again;
986    }
987
988    return (serr);
989}
990
991/*
992 * R P C _ _ S O C K E T _ R E C V F R O M
993 *
994 * Recieve the next buffer worth of information from a socket.  A
995 * rpc_addr_t appropriate for the NAF corresponding to this socket must
996 * be provided.  addr.len must set to the actual size of addr.sa.  This
997 * operation fills in addr.sa and sets addr.len to the new size of the
998 * field.  An error status as well as the actual number of bytes received
999 * are also returned.
1000 *
1001 * (see BSD UNIX recvfrom(2)).
1002 */
1003
1004INTERNAL rpc_socket_error_t rpc__bsd_socket_recvfrom
1005(
1006    rpc_socket_t        sock,
1007    byte_p_t            buf,        /* buf for rcvd data */
1008    int                 len,        /* len of above buf */
1009    rpc_addr_p_t        from,       /* addr of sender */
1010    size_t              *cc         /* returned number of bytes actually rcvd */
1011)
1012{
1013    ssize_t             ret;
1014    rpc_socket_error_t  serr;
1015    struct msghdr       msg;
1016    rpc_bsd_socket_p_t  lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1017
1018    *cc = 0;
1019
1020recvfrom_again:
1021    if (from != NULL)
1022    {
1023        RPC_SOCKET_FIX_ADDRLEN(from);
1024    }
1025
1026    RPC_LOG_SOCKET_RECVFROM_NTR;
1027
1028    ret = dcethread_recvfrom(lrpc->fd, buf, len, 0 /* flags */,
1029                    &from->sa, &from->len);
1030    if (ret == (size_t) -1)
1031    {
1032        serr = errno;
1033    }
1034    else
1035    {
1036        serr = RPC_C_SOCKET_OK;
1037        *cc = ret;
1038    }
1039
1040    RPC_LOG_SOCKET_RECVFROM_XIT;
1041    RPC_SOCKET_FIX_ADDRLEN(from);
1042    if (serr == EINTR)
1043    {
1044        goto recvfrom_again;
1045    }
1046
1047    return serr;
1048}
1049
1050/*
1051 * R P C _ _ S O C K E T _ R E C V M S G
1052 *
1053 * Receive a message over a given socket.  A rpc_addr_t appropriate for
1054 * the NAF corresponding to this socket must be provided.  addr.len must
1055 * set to the actual size of addr.sa.  This operation fills in addr.sa
1056 * and sets addr.len to the new size of the field.  An error code as
1057 * well as the actual number of bytes received are also returned.
1058 *
1059 * (see BSD UNIX recvmsg(2)).
1060 */
1061
1062INTERNAL rpc_socket_error_t rpc__bsd_socket_recvmsg
1063(
1064    rpc_socket_t        sock,
1065    rpc_socket_iovec_p_t iov,       /* array of bufs for rcvd data */
1066    int                 iovcnt,    /* number of bufs */
1067    rpc_addr_p_t        addr,       /* addr of sender */
1068    size_t              *cc         /* returned number of bytes actually rcvd */
1069)
1070{
1071    ssize_t             ret;
1072    rpc_socket_error_t  serr;
1073    struct msghdr       msg;
1074    rpc_bsd_socket_p_t  lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1075
1076    *cc = 0;
1077
1078recvmsg_again:
1079
1080    memset(&msg, 0, sizeof(msg));
1081    RPC_LOG_SOCKET_RECVMSG_NTR;
1082    RPC_SOCKET_INIT_MSGHDR(&msg);
1083    if (addr != NULL)
1084    {
1085        RPC_SOCKET_FIX_ADDRLEN(addr);
1086        msg.msg_name = (caddr_t) &addr->sa;
1087        msg.msg_namelen = addr->len;
1088    }
1089    else
1090    {
1091        msg.msg_name = (caddr_t) NULL;
1092    }
1093    msg.msg_iov =  iov;
1094    msg.msg_iovlen = iovcnt;
1095
1096    ret = dcethread_recvmsg (lrpc->fd, &msg, 0);
1097    if (ret == (ssize_t)-1)
1098    {
1099        serr = errno;
1100    }
1101    else
1102    {
1103        serr = RPC_C_SOCKET_OK;
1104        *cc = ret;
1105    }
1106
1107    RPC_LOG_SOCKET_RECVMSG_XIT;
1108    if (serr == EINTR)
1109    {
1110        goto recvmsg_again;
1111    }
1112
1113    if (addr != NULL)
1114    {
1115        addr->len = msg.msg_namelen;
1116    }
1117
1118    return serr;
1119}
1120
1121/*
1122 * R P C _ _ S O C K E T _ I N Q _ A D D R
1123 *
1124 * Return the local address associated with a socket.  A rpc_addr_t
1125 * appropriate for the NAF corresponding to this socket must be provided.
1126 * addr.len must set to the actual size of addr.sa.  This operation fills
1127 * in addr.sa and sets addr.len to the new size of the field.
1128 *
1129 * !!! NOTE: You should use rpc__naf_desc_inq_addr() !!!
1130 *
1131 * This routine is indended for use only by the internal routine:
1132 * rpc__naf_desc_inq_addr().  rpc__bsd_socket_inq_endpoint() only has the
1133 * functionality of BSD UNIX getsockname() which doesn't (at least not
1134 * on all systems) return the local network portion of a socket's address.
1135 * rpc__naf_desc_inq_addr() returns the complete address for a socket.
1136 *
1137 * (see BSD UNIX getsockname(2)).
1138 */
1139
1140INTERNAL rpc_socket_error_t rpc__bsd_socket_inq_endpoint
1141(
1142    rpc_socket_t        sock,
1143    rpc_addr_p_t        addr
1144)
1145{
1146    rpc_socket_error_t  serr;
1147    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1148
1149    RPC_LOG_SOCKET_INQ_EP_NTR;
1150    RPC_SOCKET_FIX_ADDRLEN(addr);
1151    RPC_SOCKET_DISABLE_CANCEL;
1152    serr = (getsockname(lrpc->fd, (void*)&addr->sa, &addr->len) == -1) ? errno : RPC_C_SOCKET_OK;
1153    RPC_SOCKET_RESTORE_CANCEL;
1154    RPC_SOCKET_FIX_ADDRLEN(addr);
1155    RPC_LOG_SOCKET_INQ_EP_XIT;
1156    return (serr);
1157}
1158
1159/*
1160 * R P C _ _ S O C K E T _ S E T _ B R O A D C A S T
1161 *
1162 * Enable broadcasting for the socket (as best it can).
1163 * Used only by Datagram based Protocol Services.
1164 */
1165
1166INTERNAL rpc_socket_error_t rpc__bsd_socket_set_broadcast
1167(
1168    rpc_socket_t        sock
1169)
1170{
1171#ifdef SO_BROADCAST
1172    int                 setsock_val = 1;
1173    rpc_socket_error_t  serr;
1174    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1175
1176    RPC_SOCKET_DISABLE_CANCEL;
1177    serr = (setsockopt(lrpc->fd, SOL_SOCKET, SO_BROADCAST,
1178            &setsock_val, sizeof(setsock_val)) == -1) ? errno : RPC_C_SOCKET_OK;
1179    RPC_SOCKET_RESTORE_CANCEL;
1180    if (serr)
1181    {
1182        RPC_DBG_GPRINTF(("(rpc__bsd_socket_set_broadcast) error=%d\n", serr));
1183    }
1184
1185    return(serr);
1186#else
1187    return(RPC_C_SOCKET_OK);
1188#endif
1189}
1190
1191/*
1192 * R P C _ _ S O C K E T _ S E T _ B U F S
1193 *
1194 * Set the socket's send and receive buffer sizes and return the new
1195 * values.  Note that the sizes are min'd with
1196 * "rpc_c_socket_max_{snd,rcv}buf" because systems tend to fail the
1197 * operation rather than give the max buffering if the max is exceeded.
1198 *
1199 * If for some reason your system is screwed up and defines SOL_SOCKET
1200 * and SO_SNDBUF, but doesn't actually support the SO_SNDBUF and SO_RCVBUF
1201 * operations AND using them would result in nasty behaviour (i.e. they
1202 * don't just return some error code), define NO_SO_SNDBUF.
1203 *
1204 * If the buffer sizes provided are 0, then we use the operating
1205 * system default (i.e. we don't set anything at all).
1206 */
1207
1208INTERNAL rpc_socket_error_t rpc__bsd_socket_set_bufs
1209(
1210    rpc_socket_t        sock,
1211    unsigned32          txsize,
1212    unsigned32          rxsize,
1213    unsigned32          *ntxsize,
1214    unsigned32          *nrxsize
1215)
1216{
1217    socklen_t sizelen;
1218    int e;
1219    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1220
1221    RPC_SOCKET_DISABLE_CANCEL;
1222
1223#if (defined (SOL_SOCKET) && defined(SO_SNDBUF)) && !defined(NO_SO_SNDBUF)
1224
1225    /*
1226     * Set the new sizes.
1227     */
1228
1229    txsize = MIN(txsize, RPC_C_SOCKET_MAX_SNDBUF);
1230    if (txsize != 0)
1231    {
1232        e = setsockopt(lrpc->fd, SOL_SOCKET, SO_SNDBUF, &txsize, sizeof(txsize));
1233        if (e == -1)
1234        {
1235            RPC_DBG_GPRINTF
1236                (("(rpc__bsd_socket_set_bufs) WARNING: set sndbuf (%d) failed - error = %d\n",
1237                txsize, errno));
1238        }
1239    }
1240
1241    rxsize = MIN(rxsize, RPC_C_SOCKET_MAX_RCVBUF);
1242    if (rxsize != 0)
1243    {
1244        e = setsockopt(lrpc->fd, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize));
1245        if (e == -1)
1246        {
1247            RPC_DBG_GPRINTF
1248                (("(rpc__bsd_socket_set_bufs) WARNING: set rcvbuf (%d) failed - error = %d\n",
1249                rxsize, errno));
1250        }
1251    }
1252
1253    /*
1254     * Get the new sizes.  If this fails, just return some guessed sizes.
1255     */
1256    *ntxsize = 0;
1257    sizelen = sizeof *ntxsize;
1258    e = getsockopt(lrpc->fd, SOL_SOCKET, SO_SNDBUF, ntxsize, &sizelen);
1259    if (e == -1)
1260    {
1261        RPC_DBG_GPRINTF
1262            (("(rpc__bsd_socket_set_bufs) WARNING: get sndbuf failed - error = %d\n", errno));
1263        *ntxsize = RPC_C_SOCKET_GUESSED_SNDBUF;
1264    }
1265
1266    *nrxsize = 0;
1267    sizelen = sizeof *nrxsize;
1268    e = getsockopt(lrpc->fd, SOL_SOCKET, SO_RCVBUF, nrxsize, &sizelen);
1269    if (e == -1)
1270    {
1271        RPC_DBG_GPRINTF
1272            (("(rpc__bsd_socket_set_bufs) WARNING: get rcvbuf failed - error = %d\n", errno));
1273        *nrxsize = RPC_C_SOCKET_GUESSED_RCVBUF;
1274    }
1275
1276#  ifdef apollo
1277    /*
1278     * On Apollo, modifying the socket buffering doesn't actually do
1279     * anything on IP sockets, but the calls succeed anyway.  We can
1280     * detect this by the fact that the new buffer length returned is
1281     * 0. Return what we think the actually length is.
1282     */
1283    if (rxsize != 0 && *nrxsize == 0)
1284    {
1285        *nrxsize = (8 * 1024);
1286    }
1287    if (txsize != 0 && *ntxsize == 0)
1288    {
1289        *ntxsize = (8 * 1024);
1290    }
1291#  endif
1292
1293#else
1294
1295    *ntxsize = RPC_C_SOCKET_GUESSED_SNDBUF;
1296    *nrxsize = RPC_C_SOCKET_GUESSED_RCVBUF;
1297
1298#endif
1299
1300    RPC_SOCKET_RESTORE_CANCEL;
1301
1302    return (RPC_C_SOCKET_OK);
1303}
1304
1305/*
1306 * R P C _ _ S O C K E T _ S E T _ N B I O
1307 *
1308 * Set a socket to non-blocking mode.
1309 *
1310 * Return RPC_C_SOCKET_OK on success, otherwise an error value.
1311 */
1312
1313INTERNAL rpc_socket_error_t rpc__bsd_socket_set_nbio
1314(
1315    rpc_socket_t        sock
1316)
1317{
1318    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1319    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1320
1321    RPC_SOCKET_DISABLE_CANCEL;
1322    serr = ((fcntl(lrpc->fd, F_SETFL, O_NDELAY) == -1) ? errno : RPC_C_SOCKET_OK);
1323    RPC_SOCKET_RESTORE_CANCEL;
1324    if (serr)
1325    {
1326        RPC_DBG_GPRINTF(("(rpc__bsd_socket_set_nbio) error=%d\n", serr));
1327    }
1328
1329    return (serr);
1330}
1331
1332/*
1333 * R P C _ _ S O C K E T _ S E T _ C L O S E _ O N _ E X E C
1334 *
1335 *
1336 * Set a socket to a mode whereby it is not inherited by a spawned process
1337 * executing some new image. This is possibly a no-op on some systems.
1338 *
1339 * Return RPC_C_SOCKET_OK on success, otherwise an error value.
1340 */
1341
1342INTERNAL rpc_socket_error_t rpc__bsd_socket_set_close_on_exec
1343(
1344    rpc_socket_t        sock
1345)
1346{
1347    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
1348    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1349
1350    RPC_SOCKET_DISABLE_CANCEL;
1351    serr = ((fcntl(lrpc->fd, F_SETFD, 1) == -1) ? errno : RPC_C_SOCKET_OK);
1352    RPC_SOCKET_RESTORE_CANCEL;
1353    if (serr)
1354    {
1355        RPC_DBG_GPRINTF(("(rpc__bsd_socket_set_close_on_exec) error=%d\n", serr));
1356    }
1357    return (serr);
1358}
1359
1360/*
1361 * R P C _ _ S O C K E T _ G E T P E E R N A M E
1362 *
1363 * Get name of connected peer.
1364 * This is used only by Connection oriented Protocol Services.
1365 *
1366 * (see BSD UNIX getpeername(2)).
1367 */
1368
1369INTERNAL rpc_socket_error_t rpc__bsd_socket_getpeername
1370(
1371    rpc_socket_t sock,
1372    rpc_addr_p_t addr
1373)
1374{
1375    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1376    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1377
1378    RPC_SOCKET_FIX_ADDRLEN(addr);
1379    RPC_SOCKET_DISABLE_CANCEL;
1380    serr = (getpeername(lrpc->fd, (void *)&addr->sa, &addr->len) == -1) ? errno : RPC_C_SOCKET_OK;
1381    RPC_SOCKET_RESTORE_CANCEL;
1382    RPC_SOCKET_FIX_ADDRLEN(addr);
1383
1384    return (serr);
1385}
1386
1387/*
1388 * R P C _ _ S O C K E T _ G E T _ I F _ I D
1389 *
1390 * Get socket network interface id (socket type).
1391 *
1392 * (see BSD UNIX getsockopt(2)).
1393 */
1394
1395INTERNAL rpc_socket_error_t rpc__bsd_socket_get_if_id
1396(
1397    rpc_socket_t        sock,
1398    rpc_network_if_id_t *network_if_id
1399)
1400{
1401    socklen_t optlen = 0;
1402    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1403    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1404
1405    optlen = sizeof(rpc_network_if_id_t);
1406
1407    RPC_SOCKET_DISABLE_CANCEL;
1408    serr = (getsockopt (lrpc->fd,
1409                        SOL_SOCKET,
1410                        SO_TYPE,
1411                        network_if_id,
1412                        &optlen) == -1  ? errno : RPC_C_SOCKET_OK);
1413    RPC_SOCKET_RESTORE_CANCEL;
1414    return serr;
1415}
1416
1417/*
1418 * R P C _ _ S O C K E T _ S E T _ K E E P A L I V E
1419 *
1420 * Enable periodic transmissions on a connected socket, when no
1421 * other data is being exchanged. If the other end does not respond to
1422 * these messages, the connection is considered broken and the
1423 * so_error variable is set to ETIMEDOUT.
1424 * Used only by Connection based Protocol Services.
1425 *
1426 * (see BSD UNIX setsockopt(2)).
1427 */
1428
1429INTERNAL rpc_socket_error_t rpc__bsd_socket_set_keepalive
1430(
1431    rpc_socket_t        sock
1432)
1433{
1434#ifdef SO_KEEPALIVE
1435    int                 setsock_val = 1;
1436    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
1437    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1438
1439    RPC_SOCKET_DISABLE_CANCEL;
1440    serr = ((setsockopt(lrpc->fd, SOL_SOCKET, SO_KEEPALIVE,
1441       &setsock_val, sizeof(setsock_val)) == -1) ? errno : RPC_C_SOCKET_OK);
1442    RPC_SOCKET_RESTORE_CANCEL;
1443    if (serr)
1444    {
1445        RPC_DBG_GPRINTF(("(rpc__bsd_socket_set_keepalive) error=%d\n", serr));
1446    }
1447
1448    return(serr);
1449#else
1450    return(RPC_C_SOCKET_OK);
1451#endif
1452}
1453
1454
1455/*
1456 * R P C _ _ S O C K E T _ N O W R I T E B L O C K _ W A I T
1457 *
1458 * Wait until the a write on the socket should succede without
1459 * blocking.  If tmo is NULL, the wait is unbounded, otherwise
1460 * tmo specifies the max time to wait. RPC_C_SOCKET_ETIMEDOUT
1461 * if a timeout occurs.  This operation in not cancellable.
1462 */
1463
1464INTERNAL rpc_socket_error_t rpc__bsd_socket_nowriteblock_wait
1465(
1466    rpc_socket_t sock,
1467    struct timeval *tmo
1468)
1469{
1470    fd_set  write_fds;
1471    int     nfds, num_found;
1472    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
1473    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1474
1475    FD_ZERO (&write_fds);
1476    FD_SET (lrpc->fd, &write_fds);
1477    nfds = lrpc->fd + 1;
1478
1479    RPC_SOCKET_DISABLE_CANCEL;
1480    num_found = dcethread_select(nfds, NULL, (void *)&write_fds, NULL, tmo);
1481    serr = ((num_found < 0) ? errno : RPC_C_SOCKET_OK);
1482    RPC_SOCKET_RESTORE_CANCEL;
1483
1484    if (serr)
1485    {
1486        RPC_DBG_GPRINTF(("(rpc__bsd_socket_nowriteblock_wait) error=%d\n", serr));
1487        return serr;
1488    }
1489
1490    if (num_found == 0)
1491    {
1492        RPC_DBG_GPRINTF(("(rpc__bsd_socket_nowriteblock_wait) timeout\n"));
1493        return RPC_C_SOCKET_ETIMEDOUT;
1494    }
1495
1496    return RPC_C_SOCKET_OK;
1497}
1498
1499
1500/*
1501 * R P C _ _ S O C K E T _ S E T _ R C V T I M E O
1502 *
1503 * Set receive timeout on a socket
1504 * Used only by Connection based Protocol Services.
1505 *
1506 * (see BSD UNIX setsockopt(2)).
1507 */
1508
1509INTERNAL rpc_socket_error_t rpc__bsd_socket_set_rcvtimeo
1510(
1511    rpc_socket_t        sock,
1512    struct timeval      *tmo
1513)
1514{
1515#ifdef SO_RCVTIMEO
1516    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1517    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1518
1519    RPC_SOCKET_DISABLE_CANCEL;
1520    serr = ((setsockopt(lrpc->fd, SOL_SOCKET, SO_RCVTIMEO,
1521       tmo, sizeof(*tmo)) == -1) ? errno : RPC_C_SOCKET_OK);
1522    RPC_SOCKET_RESTORE_CANCEL;
1523    if (serr)
1524    {
1525        RPC_DBG_GPRINTF(("(rpc__bsd_socket_set_rcvtimeo) error=%d\n", serr));
1526    }
1527
1528    return(serr);
1529#else
1530    return(RPC_C_SOCKET_OK);
1531#endif
1532}
1533
1534/*
1535 * R P C _ _ S O C K E T _ G E T _ P E E R E I D
1536 *
1537 * Get UNIX domain socket peer credentials
1538 */
1539
1540INTERNAL rpc_socket_error_t rpc__bsd_socket_getpeereid
1541(
1542    rpc_socket_t        sock,
1543    uid_t		*euid,
1544    gid_t		*egid
1545)
1546{
1547    rpc_socket_error_t  serr = RPC_C_SOCKET_ENOTSUP;
1548    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1549
1550#if HAVE_GETPEEREID
1551
1552    RPC_SOCKET_DISABLE_CANCEL;
1553    serr = ((getpeereid(lrpc->fd, euid, egid) == -1) ? errno
1554                                            : RPC_C_SOCKET_OK);
1555    RPC_SOCKET_RESTORE_CANCEL;
1556
1557    if (serr != RPC_C_SOCKET_OK)
1558    {
1559        RPC_DBG_GPRINTF(("(rpc__bsd_socket_getpeereid) error=%d\n", serr));
1560    }
1561
1562#elif defined(SO_PEERCRED)
1563    struct ucred peercred = {0};
1564    socklen_t peercredlen = sizeof(peercred);
1565
1566    RPC_SOCKET_DISABLE_CANCEL;
1567    serr = ((getsockopt(lrpc->fd, SOL_SOCKET, SO_PEERCRED,
1568	&peercred, &peercredlen) == -1) ? errno : RPC_C_SOCKET_OK);
1569    RPC_SOCKET_RESTORE_CANCEL;
1570    if (serr == RPC_C_SOCKET_OK)
1571    {
1572	*euid = peercred.uid;
1573	*egid = peercred.gid;
1574    }
1575    else
1576    {
1577        RPC_DBG_GPRINTF(("(rpc__bsd_socket_getpeereid) error=%d\n", serr));
1578    }
1579#else
1580    serr = rpc__bsd_socket_recvpeereid(sock, euid, egid);
1581#endif
1582
1583    return serr;
1584}
1585
1586#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
1587
1588INTERNAL rpc_socket_error_t rpc__bsd_socket_sendpeereid
1589(
1590    rpc_socket_t        sock,
1591    rpc_addr_p_t        addr
1592)
1593{
1594    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1595    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1596    struct sockaddr_un *endpoint_addr = NULL;
1597    struct stat endpoint_stat = {0};
1598    uid_t ep_uid = -1;
1599    int pipefd[2] = {-1, -1};
1600    char empty_buf[] = {'\0'};
1601    rpc_socket_iovec_t iovec = {0};
1602    union
1603    {
1604        /* Using union ensures correct alignment on some platforms */
1605        struct cmsghdr cm;
1606        char buf[CMSG_SPACE(sizeof(pipefd[0]))];
1607    } cm_un;
1608    struct msghdr msg = {0};
1609    struct cmsghdr *cmsg = NULL;
1610    int bytes_sent = 0;
1611
1612    endpoint_addr = (struct sockaddr_un *)(&addr->sa);
1613
1614    if (stat(endpoint_addr->sun_path, &endpoint_stat))
1615    {
1616        serr = errno;
1617	goto error;
1618    }
1619
1620    ep_uid = endpoint_stat.st_uid;
1621    if (ep_uid == 0 || ep_uid == getuid())
1622    {
1623        if (pipe(pipefd) != 0)
1624        {
1625                serr = errno;
1626                goto error;
1627        }
1628    }
1629
1630    iovec.iov_base     = &empty_buf;
1631    iovec.iov_len      = sizeof(empty_buf);
1632
1633    msg.msg_iov        = &iovec;
1634    msg.msg_iovlen     = 1;
1635    msg.msg_control    = cm_un.buf;
1636    msg.msg_controllen = sizeof(cm_un.buf);
1637    msg.msg_flags      = 0;
1638
1639    memset(&cm_un, 0, sizeof(cm_un));
1640
1641    cmsg = CMSG_FIRSTHDR(&msg);
1642    cmsg->cmsg_level = SOL_SOCKET;
1643    cmsg->cmsg_type  = SCM_RIGHTS;
1644    cmsg->cmsg_len   = CMSG_LEN(sizeof(pipefd[0]));
1645
1646    memcpy(CMSG_DATA(cmsg), &pipefd[0], sizeof(pipefd[0]));
1647
1648    RPC_SOCKET_DISABLE_CANCEL;
1649    bytes_sent = sendmsg(lrpc->fd, &msg, 0);
1650    RPC_SOCKET_RESTORE_CANCEL;
1651    if (bytes_sent == -1)
1652    {
1653        serr = errno;
1654        goto error;
1655    }
1656
1657cleanup:
1658
1659    if (pipefd[0] != -1)
1660    {
1661        close(pipefd[0]);
1662    }
1663
1664    if (pipefd[1] != -1)
1665    {
1666        close(pipefd[1]);
1667    }
1668
1669    return serr;
1670
1671error:
1672
1673    goto cleanup;
1674}
1675
1676INTERNAL rpc_socket_error_t rpc__bsd_socket_recvpeereid
1677(
1678    rpc_socket_t        sock,
1679    uid_t		*euid,
1680    gid_t		*egid
1681)
1682{
1683    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1684    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1685    int fd = -1;
1686    int bytes_rcvd = 0;
1687    struct stat pipe_stat = {0};
1688    char empty_buf[] = {'\0'};
1689    rpc_socket_iovec_t iovec = {0};
1690    union
1691    {
1692        /* Using union ensures correct alignment on some platforms */
1693        struct cmsghdr cm;
1694        char buf[CMSG_SPACE(sizeof(fd))];
1695    } cm_un;
1696    struct cmsghdr *cmsg = NULL;
1697    struct msghdr msg = {0};
1698
1699    iovec.iov_base = &empty_buf;
1700    iovec.iov_len  = sizeof(empty_buf);
1701
1702    memset(&cm_un, 0, sizeof(cm_un));
1703
1704    msg.msg_iov        = &iovec;
1705    msg.msg_iovlen     = 1;
1706    msg.msg_control    = cm_un.buf;
1707    msg.msg_controllen = sizeof(cm_un.buf);
1708    msg.msg_flags      = 0;
1709
1710    RPC_SOCKET_DISABLE_CANCEL;
1711    bytes_rcvd = recvmsg(lrpc->fd, &msg, 0);
1712    RPC_SOCKET_RESTORE_CANCEL;
1713    if (bytes_rcvd == -1)
1714    {
1715        serr = errno;
1716        goto error;
1717    }
1718
1719    if (msg.msg_controllen == 0 ||
1720        msg.msg_controllen > sizeof(cm_un))
1721    {
1722        serr = RPC_C_SOCKET_EACCESS;
1723        goto error;
1724    }
1725
1726    cmsg = CMSG_FIRSTHDR(&msg);
1727    if (!cmsg ||
1728	!(cmsg->cmsg_type == SCM_RIGHTS) ||
1729        cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg)) != sizeof(fd))
1730    {
1731        serr = RPC_C_SOCKET_EACCESS;
1732        goto error;
1733    }
1734
1735    memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
1736
1737    if (fstat(fd, &pipe_stat))
1738    {
1739        serr = errno;
1740        goto error;
1741    }
1742
1743    if (!S_ISFIFO(pipe_stat.st_mode) ||
1744        (pipe_stat.st_mode & (S_IRWXO | S_IRWXG)) != 0)
1745    {
1746        serr = RPC_C_SOCKET_EACCESS;
1747        goto error;
1748    }
1749
1750    *euid = pipe_stat.st_uid;
1751    *egid = pipe_stat.st_gid;
1752
1753cleanup:
1754
1755    if (fd > 0)
1756    {
1757        close(fd);
1758    }
1759
1760    return serr;
1761
1762error:
1763
1764    *euid = -1;
1765    *egid = -1;
1766
1767    goto cleanup;
1768}
1769
1770#endif
1771
1772INTERNAL
1773int rpc__bsd_socket_get_select_desc(
1774    rpc_socket_t sock
1775    )
1776{
1777    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1778
1779    return lrpc->fd;
1780}
1781
1782INTERNAL
1783rpc_socket_error_t
1784rpc__bsd_socket_enum_ifaces(
1785    rpc_socket_t sock,
1786    rpc_socket_enum_iface_fn_p_t efun,
1787    rpc_addr_vector_p_t *rpc_addr_vec,
1788    rpc_addr_vector_p_t *netmask_addr_vec,
1789    rpc_addr_vector_p_t *broadcast_addr_vec
1790)
1791{
1792    rpc_ip_addr_p_t         ip_addr = NULL;
1793    rpc_ip_addr_p_t         netmask_addr = NULL;
1794    rpc_ip_addr_p_t         broadcast_addr = NULL;
1795    int                     n_ifs;
1796    union
1797    {
1798        unsigned char           buf[1024];
1799        struct ifreq req;
1800    } reqbuf;
1801    struct ifconf           ifc;
1802    struct ifreq            *ifr, *last_ifr;
1803    struct ifreq            ifreq;
1804    short                   if_flags;
1805    struct sockaddr         if_addr;
1806    unsigned int                     i;
1807#ifdef _SOCKADDR_LEN
1808    int                     prev_size;
1809#else
1810    const int prev_size = sizeof(struct ifreq) ;
1811#endif
1812    rpc_socket_error_t err = 0;
1813    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
1814
1815    /*
1816     * Get the list of network interfaces.
1817     */
1818    ifc.ifc_len = sizeof (reqbuf.buf);
1819    ifc.ifc_buf = (caddr_t) reqbuf.buf;
1820
1821ifconf_again:
1822    if (ioctl (lrpc->fd, SIOCGIFCONF, (caddr_t) &ifc) < 0)
1823    {
1824        if (errno == EINTR)
1825        {
1826            goto ifconf_again;
1827        }
1828        err = errno;   /* !!! */
1829        goto done;
1830    }
1831
1832    /*
1833     * Figure out how many interfaces there must be and allocate an
1834     * RPC address vector with the appropriate number of elements.
1835     * (We may ask for a few too many in case some of the interfaces
1836     * are uninteresting.)
1837     */
1838    n_ifs = ifc.ifc_len / sizeof (struct ifreq);
1839    RPC_DBG_PRINTF(rpc_e_dbg_general, 10,
1840        ("%lu bytes of ifreqs, ifreq is %lu bytes\n",
1841         (unsigned long)ifc.ifc_len,
1842         (unsigned long)sizeof(struct ifreq)));
1843
1844#ifdef MAX_DEBUG
1845    if (RPC_DBG2(rpc_e_dbg_general, 15))
1846    {
1847        int i;
1848	char msgbuf[128];
1849
1850        for (i=0; i<ifc.ifc_len; i++) {
1851            if ((i % 32) == 0) {
1852		if (i != 0)
1853		    RPC_DBG_PRINTF(rpc_e_dbg_general, 15, ("%s\n",msgbuf));
1854                sprintf(msgbuf, "%4x: ", i);
1855	    }
1856            sprintf(msgbuf, "%s%02x ", msgbuf, reqbuf.buf[i]);
1857        }
1858	if (i != 0)
1859	    RPC_DBG_PRINTF(rpc_e_dbg_general, 15, ("%s\n",msgbuf));
1860    }
1861#endif
1862
1863    if (rpc_addr_vec != NULL)
1864    {
1865        RPC_MEM_ALLOC (
1866            *rpc_addr_vec,
1867            rpc_addr_vector_p_t,
1868            (sizeof **rpc_addr_vec) + ((n_ifs - 1) * (sizeof (rpc_addr_p_t))),
1869            RPC_C_MEM_RPC_ADDR_VEC,
1870            RPC_C_MEM_WAITOK);
1871
1872        if (*rpc_addr_vec == NULL)
1873        {
1874            err = ENOMEM;
1875            goto done;
1876        }
1877    }
1878
1879    if (netmask_addr_vec != NULL)
1880    {
1881        RPC_MEM_ALLOC (
1882            *netmask_addr_vec,
1883            rpc_addr_vector_p_t,
1884         (sizeof **netmask_addr_vec) + ((n_ifs - 1) * (sizeof (rpc_addr_p_t))),
1885            RPC_C_MEM_RPC_ADDR_VEC,
1886            RPC_C_MEM_WAITOK);
1887
1888        if (*netmask_addr_vec == NULL)
1889        {
1890            err = ENOMEM;
1891            RPC_MEM_FREE (*netmask_addr_vec, RPC_C_MEM_RPC_ADDR_VEC);
1892            goto done;
1893        }
1894
1895        (*netmask_addr_vec)->len = 0;
1896    }
1897
1898    if (broadcast_addr_vec != NULL)
1899    {
1900        RPC_MEM_ALLOC (
1901            *broadcast_addr_vec,
1902            rpc_addr_vector_p_t,
1903         (sizeof **broadcast_addr_vec) + ((n_ifs - 1) * (sizeof (rpc_addr_p_t))),
1904            RPC_C_MEM_RPC_ADDR_VEC,
1905            RPC_C_MEM_WAITOK);
1906
1907        if (*broadcast_addr_vec == NULL)
1908        {
1909            err = ENOMEM;
1910            RPC_MEM_FREE (*broadcast_addr_vec, RPC_C_MEM_RPC_ADDR_VEC);
1911            goto done;
1912        }
1913
1914        (*broadcast_addr_vec)->len = 0;
1915    }
1916
1917    /*
1918     * Go through the interfaces and get the info associated with them.
1919     */
1920    assert(rpc_addr_vec != NULL);
1921    (*rpc_addr_vec)->len = 0;
1922    last_ifr = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1923
1924    for (i=0, ifr = ifc.ifc_req; ifr < last_ifr ;
1925         i++, ifr = (struct ifreq *)(( (char *) ifr ) + prev_size))
1926    {
1927#ifdef _SOCKADDR_LEN
1928        prev_size = sizeof (struct ifreq) - sizeof(struct sockaddr) + ifr->ifr_addr.sa_len ;
1929#endif
1930        RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("interface %d: %s\n",
1931            i, ifr->ifr_name));
1932        /*
1933         * Get the interface's flags.  If the flags say that the interface
1934         * is not up or is the loopback interface, skip it.  Do the
1935         * SIOCGIFFLAGS on a copy of the ifr so we don't lose the original
1936         * contents of the ifr.  (ifr's are unions that hold only one
1937         * of the interesting interface attributes [address, flags, etc.]
1938         * at a time.)
1939         */
1940        memcpy(&ifreq, ifr, sizeof(ifreq));
1941ifflags_again:
1942        if (ioctl(lrpc->fd, SIOCGIFFLAGS, &ifreq) < 0)
1943        {
1944            RPC_DBG_PRINTF(rpc_e_dbg_general, 10,
1945                ("SIOCGIFFLAGS returned errno %d\n", errno));
1946            if (errno == EINTR)
1947            {
1948                goto ifflags_again;
1949            }
1950            continue;
1951        }
1952        if_flags = ifreq.ifr_flags;     /* Copy out the flags */
1953        RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("flags are %x\n", if_flags));
1954
1955        /*
1956         * Ignore interfaces which are not 'up'.
1957         */
1958        if ((if_flags & IFF_UP) == 0)
1959
1960	  continue;
1961
1962#ifndef USE_LOOPBACK
1963	/*
1964	 * Ignore the loopback interface
1965	 */
1966
1967        if (if_flags & IFF_LOOPBACK) continue;
1968#endif
1969	/*
1970	 * Ignore Point-to-Point interfaces (i.e. SLIP/PPP )
1971         * *** NOTE:  We need an Environment Variable Evaluation at
1972	 * some point so we can selectively allow RPC servers to
1973	 * some up with/without SLIP/PPP bindings. For Dynamic PPP/SLIP
1974	 * interfaces, this creates problems for now.
1975	 */
1976
1977        if (if_flags & IFF_POINTOPOINT) continue;
1978
1979        /*
1980         * Get the addressing stuff for this interface.
1981         */
1982
1983#ifdef NO_SIOCGIFADDR
1984
1985        /*
1986         * Note that some systems do not return the address for the
1987         * interface given.  However the ifr array elts contained in
1988         * the ifc block returned from the SIOCGIFCONF ioctl above already
1989         * contains the correct addresses. So these systems should define
1990         * NO_SIOCGIFADDR in their platform specific include file.
1991         */
1992        if_addr = ifr->ifr_addr;
1993
1994#else
1995
1996        /*
1997         * Do the SIOCGIFADDR on a copy of the ifr.  See above.
1998         */
1999        memcpy(&ifreq, ifr, sizeof(ifreq));
2000    ifaddr_again:
2001        if (ioctl(lrpc->fd, SIOCGIFADDR, &ifreq) < 0)
2002        {
2003            /*
2004             * UP but no ip address, skip it
2005             */
2006            if (errno == EADDRNOTAVAIL) continue;
2007
2008            RPC_DBG_PRINTF(rpc_e_dbg_general, 10,
2009                           ("SIOCGIFADDR returned errno %d\n", errno));
2010            if (errno == EINTR)
2011            {
2012                goto ifaddr_again;
2013            }
2014
2015            err = errno;
2016            goto FREE_IT;
2017        }
2018
2019        memcpy (&if_addr, &ifr->ifr_addr, sizeof(struct sockaddr));
2020
2021#endif  /* NO_SIOCGIFADDR */
2022
2023        /*
2024         * If this isn't an Internet-family address, ignore it.
2025         */
2026        if (if_addr.sa_family != AF_INET)
2027        {
2028            RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("AF %d not INET\n",
2029                                                   if_addr.sa_family));
2030            continue;
2031        }
2032
2033        if (rpc_addr_vec != NULL)
2034        {
2035            /*
2036             * Allocate and fill in an IP RPC address for this interface.
2037             */
2038            RPC_MEM_ALLOC (
2039                ip_addr,
2040                rpc_ip_addr_p_t,
2041                sizeof (rpc_ip_addr_t),
2042                RPC_C_MEM_RPC_ADDR,
2043                RPC_C_MEM_WAITOK);
2044
2045            if (ip_addr == NULL)
2046            {
2047                err = ENOMEM;
2048                goto FREE_IT;
2049            }
2050
2051            ip_addr->rpc_protseq_id = sock->pseq_id;
2052            ip_addr->len            = sizeof (struct sockaddr_in);
2053
2054            memcpy (&ip_addr->sa, &if_addr, sizeof(struct sockaddr_in));
2055        }
2056        else
2057        {
2058            ip_addr = NULL;
2059        }
2060
2061        if (netmask_addr_vec != NULL && (if_flags & IFF_LOOPBACK) == 0)
2062        {
2063            memcpy(&ifreq, ifr, sizeof(ifreq));
2064
2065            while (ioctl(lrpc->fd, SIOCGIFNETMASK, &ifreq) == -1)
2066            {
2067                if (errno != EINTR)
2068                {
2069                    err = errno;
2070                    goto FREE_IT;
2071                }
2072            }
2073
2074            RPC_MEM_ALLOC (
2075                netmask_addr,
2076                rpc_ip_addr_p_t,
2077                sizeof (rpc_ip_addr_t),
2078                RPC_C_MEM_RPC_ADDR,
2079                RPC_C_MEM_WAITOK);
2080
2081            if (netmask_addr == NULL)
2082            {
2083                err = ENOMEM;
2084                goto FREE_IT;
2085            }
2086
2087            netmask_addr->rpc_protseq_id = sock->pseq_id;
2088            netmask_addr->len            = sizeof (struct sockaddr_in);
2089            memcpy(&netmask_addr->sa, &ifreq.ifr_addr, sizeof(struct sockaddr_in));
2090        }
2091        else
2092        {
2093            netmask_addr = NULL;
2094        }
2095
2096        if (broadcast_addr_vec != NULL && (if_flags & IFF_BROADCAST))
2097        {
2098            memcpy(&ifreq, ifr, sizeof(ifreq));
2099
2100            while (ioctl(lrpc->fd, SIOCGIFBRDADDR, &ifreq) == -1)
2101            {
2102                if (errno != EINTR)
2103                {
2104                    err = errno;
2105                    goto FREE_IT;
2106                }
2107            }
2108
2109            RPC_MEM_ALLOC (
2110                broadcast_addr,
2111                rpc_ip_addr_p_t,
2112                sizeof (rpc_ip_addr_t),
2113                RPC_C_MEM_RPC_ADDR,
2114                RPC_C_MEM_WAITOK);
2115
2116            if (broadcast_addr == NULL)
2117            {
2118                err = ENOMEM;
2119                goto FREE_IT;
2120            }
2121
2122            broadcast_addr->rpc_protseq_id = sock->pseq_id;
2123            broadcast_addr->len            = sizeof (struct sockaddr_in);
2124            memcpy(&broadcast_addr->sa, &ifreq.ifr_broadaddr, sizeof(struct sockaddr_in));
2125        }
2126        else
2127        {
2128            broadcast_addr = NULL;
2129        }
2130
2131        /*
2132         * Call out to do any final filtering and get the desired IP address
2133         * for this interface.  If the callout function returns false, we
2134         * forget about this interface.
2135         */
2136        if ((*efun) (sock, (rpc_addr_p_t) ip_addr, (rpc_addr_p_t) netmask_addr, (rpc_addr_p_t) broadcast_addr) == false)
2137        {
2138            if (ip_addr != NULL)
2139            {
2140                RPC_MEM_FREE (ip_addr, RPC_C_MEM_RPC_ADDR);
2141                ip_addr = NULL;
2142            }
2143            if (netmask_addr != NULL)
2144            {
2145                RPC_MEM_FREE (netmask_addr, RPC_C_MEM_RPC_ADDR);
2146                netmask_addr = NULL;
2147            }
2148            if (broadcast_addr != NULL)
2149            {
2150                RPC_MEM_FREE (broadcast_addr, RPC_C_MEM_RPC_ADDR);
2151                broadcast_addr = NULL;
2152            }
2153            continue;
2154        }
2155
2156        if (rpc_addr_vec != NULL && ip_addr != NULL)
2157        {
2158            (*rpc_addr_vec)->addrs[(*rpc_addr_vec)->len++]
2159                = (rpc_addr_p_t) ip_addr;
2160            ip_addr = NULL;
2161        }
2162        if (netmask_addr_vec != NULL && netmask_addr != NULL)
2163        {
2164            (*netmask_addr_vec)->addrs[(*netmask_addr_vec)->len++]
2165                = (rpc_addr_p_t) netmask_addr;
2166            netmask_addr = NULL;
2167        }
2168        if (broadcast_addr_vec != NULL && broadcast_addr != NULL)
2169        {
2170            (*broadcast_addr_vec)->addrs[(*broadcast_addr_vec)->len++]
2171                = (rpc_addr_p_t) broadcast_addr;
2172            broadcast_addr = NULL;
2173        }
2174    }
2175
2176    if ((*rpc_addr_vec)->len == 0)
2177    {
2178        err = EINVAL;   /* !!! */
2179        goto FREE_IT;
2180    }
2181
2182    err = RPC_C_SOCKET_OK;
2183done:
2184
2185    return err;
2186
2187FREE_IT:
2188
2189    if (ip_addr != NULL)
2190    {
2191        RPC_MEM_FREE (ip_addr, RPC_C_MEM_RPC_ADDR);
2192    }
2193    if (netmask_addr != NULL)
2194    {
2195        RPC_MEM_FREE (netmask_addr, RPC_C_MEM_RPC_ADDR);
2196    }
2197    if (broadcast_addr != NULL)
2198    {
2199        RPC_MEM_FREE (broadcast_addr, RPC_C_MEM_RPC_ADDR);
2200    }
2201
2202    if (rpc_addr_vec != NULL && *rpc_addr_vec != NULL)
2203    {
2204        for (i = 0; i < (*rpc_addr_vec)->len; i++)
2205        {
2206            RPC_MEM_FREE ((*rpc_addr_vec)->addrs[i], RPC_C_MEM_RPC_ADDR);
2207        }
2208        RPC_MEM_FREE (*rpc_addr_vec, RPC_C_MEM_RPC_ADDR_VEC);
2209        *rpc_addr_vec = NULL;
2210    }
2211    if (netmask_addr_vec != NULL && *netmask_addr_vec != NULL)
2212    {
2213        for (i = 0; i < (*netmask_addr_vec)->len; i++)
2214        {
2215            RPC_MEM_FREE ((*netmask_addr_vec)->addrs[i], RPC_C_MEM_RPC_ADDR);
2216        }
2217        RPC_MEM_FREE (*netmask_addr_vec, RPC_C_MEM_RPC_ADDR_VEC);
2218        *netmask_addr_vec = NULL;
2219    }
2220    if (broadcast_addr_vec != NULL && *broadcast_addr_vec != NULL)
2221    {
2222        assert(broadcast_addr_vec != NULL);
2223        for (i = 0; i < (*broadcast_addr_vec)->len; i++)
2224        {
2225            RPC_MEM_FREE ((*broadcast_addr_vec)->addrs[i], RPC_C_MEM_RPC_ADDR);
2226        }
2227        RPC_MEM_FREE (*broadcast_addr_vec, RPC_C_MEM_RPC_ADDR_VEC);
2228        *broadcast_addr_vec = NULL;
2229    }
2230
2231    goto done;
2232}
2233
2234INTERNAL
2235rpc_socket_error_t
2236rpc__bsd_socket_inq_transport_info(
2237    rpc_socket_t sock ATTRIBUTE_UNUSED,
2238    rpc_transport_info_handle_t* info
2239    )
2240{
2241    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2242    rpc_bsd_socket_p_t lrpc = (rpc_bsd_socket_p_t) sock->data.pointer;
2243    rpc_bsd_transport_info_p_t lrpc_info = NULL;
2244
2245    lrpc_info = calloc(1, sizeof(*lrpc_info));
2246
2247    if (!lrpc_info)
2248    {
2249        serr = ENOMEM;
2250	goto error;
2251    }
2252
2253    lrpc_info->peer_uid = lrpc->info.peer_uid;
2254    lrpc_info->peer_gid = lrpc->info.peer_gid;
2255
2256    *info = (rpc_transport_info_handle_t) lrpc_info;
2257
2258error:
2259    if (serr)
2260    {
2261        *info = NULL;
2262
2263	if (lrpc_info)
2264        {
2265            rpc_lrpc_transport_info_free((rpc_transport_info_handle_t) lrpc_info);
2266        }
2267    }
2268
2269    return serr;
2270}
2271
2272void
2273rpc_lrpc_transport_info_free(
2274    rpc_transport_info_handle_t info
2275    )
2276{
2277    if (info)
2278    {
2279        free(info);
2280    }
2281}
2282
2283void
2284rpc_lrpc_transport_info_inq_peer_eid(
2285    rpc_transport_info_handle_t info,
2286    unsigned32                  *uid,
2287    unsigned32                  *gid
2288    )
2289{
2290    rpc_bsd_transport_info_p_t lrpc_info = (rpc_bsd_transport_info_p_t) info;
2291
2292    if (uid)
2293    {
2294        *uid = lrpc_info->peer_uid;
2295    }
2296
2297    if (gid)
2298    {
2299        *gid = lrpc_info->peer_gid;
2300    }
2301}
2302
2303INTERNAL
2304boolean
2305rpc__bsd_socket_transport_info_equal(
2306    rpc_transport_info_handle_t info1,
2307    rpc_transport_info_handle_t info2
2308    )
2309{
2310    rpc_bsd_transport_info_p_t bsd_info1 = (rpc_bsd_transport_info_p_t) info1;
2311    rpc_bsd_transport_info_p_t bsd_info2 = (rpc_bsd_transport_info_p_t) info2;
2312
2313    if ((bsd_info1 != NULL) && (bsd_info2 != NULL))
2314    {
2315        return
2316            (bsd_info1->peer_uid == bsd_info2->peer_uid &&
2317             bsd_info1->peer_gid == bsd_info2->peer_gid);
2318    } else if (bsd_info1 == bsd_info2){
2319        return true;
2320    }
2321
2322    rpc_bsd_transport_info_p_t tmp = bsd_info1 != NULL ? bsd_info1: bsd_info2;
2323    return  (tmp->peer_uid == getuid() && tmp->peer_gid == getgid());
2324}
2325
2326INTERNAL
2327rpc_socket_error_t
2328rpc__bsd_socket_transport_inq_access_token(
2329    rpc_transport_info_handle_t info ATTRIBUTE_UNUSED,
2330    rpc_access_token_p_t* token ATTRIBUTE_UNUSED
2331    )
2332{
2333#if HAVE_LIKEWISE_LWMAPSECURITY
2334    rpc_bsd_transport_info_p_t lrpc_info = (rpc_bsd_transport_info_p_t) info;
2335    NTSTATUS status = STATUS_SUCCESS;
2336    PLW_MAP_SECURITY_CONTEXT context = NULL;
2337
2338    status = LwMapSecurityCreateContext(&context);
2339    if (status) goto error;
2340
2341    status = LwMapSecurityCreateAccessTokenFromUidGid(
2342        context,
2343        token,
2344        lrpc_info->peer_uid,
2345        lrpc_info->peer_gid);
2346    if (status) goto error;
2347
2348error:
2349
2350    LwMapSecurityFreeContext(&context);
2351
2352    return LwNtStatusToErrno(status);
2353#else
2354    return RPC_C_SOCKET_ENOTSUP;
2355#endif
2356}
2357
2358PRIVATE const rpc_socket_vtbl_t rpc_g_bsd_socket_vtbl =
2359{
2360    .socket_duplicate = rpc__bsd_socket_duplicate,
2361    .socket_construct = rpc__bsd_socket_construct,
2362    .socket_destruct = rpc__bsd_socket_destruct,
2363    .socket_bind = rpc__bsd_socket_bind,
2364    .socket_connect = rpc__bsd_socket_connect,
2365    .socket_accept = rpc__bsd_socket_accept,
2366    .socket_listen = rpc__bsd_socket_listen,
2367    .socket_sendmsg = rpc__bsd_socket_sendmsg,
2368    .socket_recvfrom = rpc__bsd_socket_recvfrom,
2369    .socket_recvmsg = rpc__bsd_socket_recvmsg,
2370    .socket_inq_endpoint = rpc__bsd_socket_inq_endpoint,
2371    .socket_set_broadcast = rpc__bsd_socket_set_broadcast,
2372    .socket_set_bufs = rpc__bsd_socket_set_bufs,
2373    .socket_set_nbio = rpc__bsd_socket_set_nbio,
2374    .socket_set_close_on_exec = rpc__bsd_socket_set_close_on_exec,
2375    .socket_getpeername = rpc__bsd_socket_getpeername,
2376    .socket_get_if_id = rpc__bsd_socket_get_if_id,
2377    .socket_set_keepalive = rpc__bsd_socket_set_keepalive,
2378    .socket_nowriteblock_wait = rpc__bsd_socket_nowriteblock_wait,
2379    .socket_set_rcvtimeo = rpc__bsd_socket_set_rcvtimeo,
2380    .socket_getpeereid = rpc__bsd_socket_getpeereid,
2381    .socket_get_select_desc = rpc__bsd_socket_get_select_desc,
2382    .socket_enum_ifaces = rpc__bsd_socket_enum_ifaces,
2383    .socket_inq_transport_info = rpc__bsd_socket_inq_transport_info,
2384    .transport_info_free = rpc_lrpc_transport_info_free,
2385    .transport_info_equal = rpc__bsd_socket_transport_info_equal,
2386    .transport_inq_access_token = rpc__bsd_socket_transport_inq_access_token
2387};
2388