]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libc/rpc/rpc_generic.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libc / rpc / rpc_generic.c
1 /*      $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $   */
2
3 /*-
4  * Copyright (c) 2009, Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions are met:
9  * - Redistributions of source code must retain the above copyright notice, 
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  *   this list of conditions and the following disclaimer in the documentation 
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
15  *   contributors may be used to endorse or promote products derived 
16  *   from this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*
31  * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
32  */
33
34 /* #pragma ident        "@(#)rpc_generic.c      1.17    94/04/24 SMI" */
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39  * rpc_generic.c, Miscl routines for RPC.
40  *
41  */
42
43 #include "namespace.h"
44 #include "reentrant.h"
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <sys/time.h>
49 #include <sys/un.h>
50 #include <sys/resource.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <rpc/rpc.h>
54 #include <ctype.h>
55 #include <stddef.h>
56 #include <stdio.h>
57 #include <netdb.h>
58 #include <netconfig.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <syslog.h>
62 #include <rpc/nettype.h>
63 #include "un-namespace.h"
64 #include "rpc_com.h"
65 #include "mt_misc.h"
66
67 struct handle {
68         NCONF_HANDLE *nhandle;
69         int nflag;              /* Whether NETPATH or NETCONFIG */
70         int nettype;
71 };
72
73 static const struct _rpcnettype {
74         const char *name;
75         const int type;
76 } _rpctypelist[] = {
77         { "netpath", _RPC_NETPATH },
78         { "visible", _RPC_VISIBLE },
79         { "circuit_v", _RPC_CIRCUIT_V },
80         { "datagram_v", _RPC_DATAGRAM_V },
81         { "circuit_n", _RPC_CIRCUIT_N },
82         { "datagram_n", _RPC_DATAGRAM_N },
83         { "tcp", _RPC_TCP },
84         { "udp", _RPC_UDP },
85         { 0, _RPC_NONE }
86 };
87
88 struct netid_af {
89         const char      *netid;
90         int             af;
91         int             protocol;
92 };
93
94 static const struct netid_af na_cvt[] = {
95         { "udp",  AF_INET,  IPPROTO_UDP },
96         { "tcp",  AF_INET,  IPPROTO_TCP },
97 #ifdef INET6
98         { "udp6", AF_INET6, IPPROTO_UDP },
99         { "tcp6", AF_INET6, IPPROTO_TCP },
100 #endif
101         { "local", AF_LOCAL, 0 }
102 };
103
104 #if 0
105 static char *strlocase(char *);
106 #endif
107 static int getnettype(const char *);
108
109 /*
110  * Cache the result of getrlimit(), so we don't have to do an
111  * expensive call every time.
112  */
113 int
114 __rpc_dtbsize()
115 {
116         static int tbsize;
117         struct rlimit rl;
118
119         if (tbsize) {
120                 return (tbsize);
121         }
122         if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
123                 return (tbsize = (int)rl.rlim_max);
124         }
125         /*
126          * Something wrong.  I'll try to save face by returning a
127          * pessimistic number.
128          */
129         return (32);
130 }
131
132
133 /*
134  * Find the appropriate buffer size
135  */
136 u_int
137 /*ARGSUSED*/
138 __rpc_get_t_size(af, proto, size)
139         int af, proto;
140         int size;       /* Size requested */
141 {
142         int maxsize, defsize;
143
144         maxsize = 256 * 1024;   /* XXX */
145         switch (proto) {
146         case IPPROTO_TCP:
147                 defsize = 64 * 1024;    /* XXX */
148                 break;
149         case IPPROTO_UDP:
150                 defsize = UDPMSGSIZE;
151                 break;
152         default:
153                 defsize = RPC_MAXDATASIZE;
154                 break;
155         }
156         if (size == 0)
157                 return defsize;
158
159         /* Check whether the value is within the upper max limit */
160         return (size > maxsize ? (u_int)maxsize : (u_int)size);
161 }
162
163 /*
164  * Find the appropriate address buffer size
165  */
166 u_int
167 __rpc_get_a_size(af)
168         int af;
169 {
170         switch (af) {
171         case AF_INET:
172                 return sizeof (struct sockaddr_in);
173 #ifdef INET6
174         case AF_INET6:
175                 return sizeof (struct sockaddr_in6);
176 #endif
177         case AF_LOCAL:
178                 return sizeof (struct sockaddr_un);
179         default:
180                 break;
181         }
182         return ((u_int)RPC_MAXADDRSIZE);
183 }
184
185 #if 0
186 static char *
187 strlocase(p)
188         char *p;
189 {
190         char *t = p;
191
192         for (; *p; p++)
193                 if (isupper(*p))
194                         *p = tolower(*p);
195         return (t);
196 }
197 #endif
198
199 /*
200  * Returns the type of the network as defined in <rpc/nettype.h>
201  * If nettype is NULL, it defaults to NETPATH.
202  */
203 static int
204 getnettype(nettype)
205         const char *nettype;
206 {
207         int i;
208
209         if ((nettype == NULL) || (nettype[0] == 0)) {
210                 return (_RPC_NETPATH);  /* Default */
211         }
212
213 #if 0
214         nettype = strlocase(nettype);
215 #endif
216         for (i = 0; _rpctypelist[i].name; i++)
217                 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
218                         return (_rpctypelist[i].type);
219                 }
220         return (_rpctypelist[i].type);
221 }
222
223 static thread_key_t tcp_key, udp_key;
224 static once_t keys_once = ONCE_INITIALIZER;
225 static int tcp_key_error, udp_key_error;
226
227 static void
228 keys_init(void)
229 {
230
231         tcp_key_error = thr_keycreate(&tcp_key, free);
232         udp_key_error = thr_keycreate(&udp_key, free);
233 }
234
235 /*
236  * For the given nettype (tcp or udp only), return the first structure found.
237  * This should be freed by calling freenetconfigent()
238  */
239 struct netconfig *
240 __rpc_getconfip(nettype)
241         const char *nettype;
242 {
243         char *netid;
244         char *netid_tcp = (char *) NULL;
245         char *netid_udp = (char *) NULL;
246         static char *netid_tcp_main;
247         static char *netid_udp_main;
248         struct netconfig *dummy;
249         int main_thread;
250
251         if ((main_thread = thr_main())) {
252                 netid_udp = netid_udp_main;
253                 netid_tcp = netid_tcp_main;
254         } else {
255                 if (thr_once(&keys_once, keys_init) != 0 ||
256                     tcp_key_error != 0 || udp_key_error != 0)
257                         return (NULL);
258                 netid_tcp = (char *)thr_getspecific(tcp_key);
259                 netid_udp = (char *)thr_getspecific(udp_key);
260         }
261         if (!netid_udp && !netid_tcp) {
262                 struct netconfig *nconf;
263                 void *confighandle;
264
265                 if (!(confighandle = setnetconfig())) {
266                         syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
267                         return (NULL);
268                 }
269                 while ((nconf = getnetconfig(confighandle)) != NULL) {
270                         if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
271                                 if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
272                                     netid_tcp == NULL) {
273                                         netid_tcp = strdup(nconf->nc_netid);
274                                         if (main_thread)
275                                                 netid_tcp_main = netid_tcp;
276                                         else
277                                                 thr_setspecific(tcp_key,
278                                                         (void *) netid_tcp);
279                                 } else
280                                 if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
281                                     netid_udp == NULL) {
282                                         netid_udp = strdup(nconf->nc_netid);
283                                         if (main_thread)
284                                                 netid_udp_main = netid_udp;
285                                         else
286                                                 thr_setspecific(udp_key,
287                                                 (void *) netid_udp);
288                                 }
289                         }
290                 }
291                 endnetconfig(confighandle);
292         }
293         if (strcmp(nettype, "udp") == 0)
294                 netid = netid_udp;
295         else if (strcmp(nettype, "tcp") == 0)
296                 netid = netid_tcp;
297         else {
298                 return (NULL);
299         }
300         if ((netid == NULL) || (netid[0] == 0)) {
301                 return (NULL);
302         }
303         dummy = getnetconfigent(netid);
304         return (dummy);
305 }
306
307 /*
308  * Returns the type of the nettype, which should then be used with
309  * __rpc_getconf().
310  */
311 void *
312 __rpc_setconf(nettype)
313         const char *nettype;
314 {
315         struct handle *handle;
316
317         handle = (struct handle *) malloc(sizeof (struct handle));
318         if (handle == NULL) {
319                 return (NULL);
320         }
321         switch (handle->nettype = getnettype(nettype)) {
322         case _RPC_NETPATH:
323         case _RPC_CIRCUIT_N:
324         case _RPC_DATAGRAM_N:
325                 if (!(handle->nhandle = setnetpath()))
326                         goto failed;
327                 handle->nflag = TRUE;
328                 break;
329         case _RPC_VISIBLE:
330         case _RPC_CIRCUIT_V:
331         case _RPC_DATAGRAM_V:
332         case _RPC_TCP:
333         case _RPC_UDP:
334                 if (!(handle->nhandle = setnetconfig())) {
335                         syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
336                         goto failed;
337                 }
338                 handle->nflag = FALSE;
339                 break;
340         default:
341                 goto failed;
342         }
343
344         return (handle);
345
346 failed:
347         free(handle);
348         return (NULL);
349 }
350
351 /*
352  * Returns the next netconfig struct for the given "net" type.
353  * __rpc_setconf() should have been called previously.
354  */
355 struct netconfig *
356 __rpc_getconf(vhandle)
357         void *vhandle;
358 {
359         struct handle *handle;
360         struct netconfig *nconf;
361
362         handle = (struct handle *)vhandle;
363         if (handle == NULL) {
364                 return (NULL);
365         }
366         for (;;) {
367                 if (handle->nflag)
368                         nconf = getnetpath(handle->nhandle);
369                 else
370                         nconf = getnetconfig(handle->nhandle);
371                 if (nconf == NULL)
372                         break;
373                 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
374                         (nconf->nc_semantics != NC_TPI_COTS) &&
375                         (nconf->nc_semantics != NC_TPI_COTS_ORD))
376                         continue;
377                 switch (handle->nettype) {
378                 case _RPC_VISIBLE:
379                         if (!(nconf->nc_flag & NC_VISIBLE))
380                                 continue;
381                         /* FALLTHROUGH */
382                 case _RPC_NETPATH:      /* Be happy */
383                         break;
384                 case _RPC_CIRCUIT_V:
385                         if (!(nconf->nc_flag & NC_VISIBLE))
386                                 continue;
387                         /* FALLTHROUGH */
388                 case _RPC_CIRCUIT_N:
389                         if ((nconf->nc_semantics != NC_TPI_COTS) &&
390                                 (nconf->nc_semantics != NC_TPI_COTS_ORD))
391                                 continue;
392                         break;
393                 case _RPC_DATAGRAM_V:
394                         if (!(nconf->nc_flag & NC_VISIBLE))
395                                 continue;
396                         /* FALLTHROUGH */
397                 case _RPC_DATAGRAM_N:
398                         if (nconf->nc_semantics != NC_TPI_CLTS)
399                                 continue;
400                         break;
401                 case _RPC_TCP:
402                         if (((nconf->nc_semantics != NC_TPI_COTS) &&
403                                 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
404                                 (strcmp(nconf->nc_protofmly, NC_INET)
405 #ifdef INET6
406                                  && strcmp(nconf->nc_protofmly, NC_INET6))
407 #else
408                                 )
409 #endif
410                                 ||
411                                 strcmp(nconf->nc_proto, NC_TCP))
412                                 continue;
413                         break;
414                 case _RPC_UDP:
415                         if ((nconf->nc_semantics != NC_TPI_CLTS) ||
416                                 (strcmp(nconf->nc_protofmly, NC_INET)
417 #ifdef INET6
418                                 && strcmp(nconf->nc_protofmly, NC_INET6))
419 #else
420                                 )
421 #endif
422                                 ||
423                                 strcmp(nconf->nc_proto, NC_UDP))
424                                 continue;
425                         break;
426                 }
427                 break;
428         }
429         return (nconf);
430 }
431
432 void
433 __rpc_endconf(vhandle)
434         void * vhandle;
435 {
436         struct handle *handle;
437
438         handle = (struct handle *) vhandle;
439         if (handle == NULL) {
440                 return;
441         }
442         if (handle->nflag) {
443                 endnetpath(handle->nhandle);
444         } else {
445                 endnetconfig(handle->nhandle);
446         }
447         free(handle);
448 }
449
450 /*
451  * Used to ping the NULL procedure for clnt handle.
452  * Returns NULL if fails, else a non-NULL pointer.
453  */
454 void *
455 rpc_nullproc(clnt)
456         CLIENT *clnt;
457 {
458         struct timeval TIMEOUT = {25, 0};
459
460         if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
461                 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
462                 return (NULL);
463         }
464         return ((void *) clnt);
465 }
466
467 /*
468  * Try all possible transports until
469  * one succeeds in finding the netconf for the given fd.
470  */
471 struct netconfig *
472 __rpcgettp(fd)
473         int fd;
474 {
475         const char *netid;
476         struct __rpc_sockinfo si;
477
478         if (!__rpc_fd2sockinfo(fd, &si))
479                 return NULL;
480
481         if (!__rpc_sockinfo2netid(&si, &netid))
482                 return NULL;
483
484         /*LINTED const castaway*/
485         return getnetconfigent((char *)netid);
486 }
487
488 int
489 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
490 {
491         socklen_t len;
492         int type, proto;
493         struct sockaddr_storage ss;
494
495         len = sizeof ss;
496         if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
497                 return 0;
498         sip->si_alen = len;
499
500         len = sizeof type;
501         if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
502                 return 0;
503
504         /* XXX */
505         if (ss.ss_family != AF_LOCAL) {
506                 if (type == SOCK_STREAM)
507                         proto = IPPROTO_TCP;
508                 else if (type == SOCK_DGRAM)
509                         proto = IPPROTO_UDP;
510                 else
511                         return 0;
512         } else
513                 proto = 0;
514
515         sip->si_af = ss.ss_family;
516         sip->si_proto = proto;
517         sip->si_socktype = type;
518
519         return 1;
520 }
521
522 /*
523  * Linear search, but the number of entries is small.
524  */
525 int
526 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
527 {
528         int i;
529
530         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
531                 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
532                     strcmp(nconf->nc_netid, "unix") == 0 &&
533                     strcmp(na_cvt[i].netid, "local") == 0)) {
534                         sip->si_af = na_cvt[i].af;
535                         sip->si_proto = na_cvt[i].protocol;
536                         sip->si_socktype =
537                             __rpc_seman2socktype((int)nconf->nc_semantics);
538                         if (sip->si_socktype == -1)
539                                 return 0;
540                         sip->si_alen = __rpc_get_a_size(sip->si_af);
541                         return 1;
542                 }
543
544         return 0;
545 }
546
547 int
548 __rpc_nconf2fd(const struct netconfig *nconf)
549 {
550         struct __rpc_sockinfo si;
551
552         if (!__rpc_nconf2sockinfo(nconf, &si))
553                 return 0;
554
555         return _socket(si.si_af, si.si_socktype, si.si_proto);
556 }
557
558 int
559 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
560 {
561         int i;
562         struct netconfig *nconf;
563
564         nconf = getnetconfigent("local");
565
566         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
567                 if (na_cvt[i].af == sip->si_af &&
568                     na_cvt[i].protocol == sip->si_proto) {
569                         if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
570                                 if (netid)
571                                         *netid = "unix";
572                         } else {
573                                 if (netid)
574                                         *netid = na_cvt[i].netid;
575                         }
576                         if (nconf != NULL)
577                                 freenetconfigent(nconf);
578                         return 1;
579                 }
580         }
581         if (nconf != NULL)
582                 freenetconfigent(nconf);
583
584         return 0;
585 }
586
587 char *
588 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
589 {
590         struct __rpc_sockinfo si;
591
592         if (!__rpc_nconf2sockinfo(nconf, &si))
593                 return NULL;
594         return __rpc_taddr2uaddr_af(si.si_af, nbuf);
595 }
596
597 struct netbuf *
598 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
599 {
600         struct __rpc_sockinfo si;
601         
602         if (!__rpc_nconf2sockinfo(nconf, &si))
603                 return NULL;
604         return __rpc_uaddr2taddr_af(si.si_af, uaddr);
605 }
606
607 char *
608 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
609 {
610         char *ret;
611         struct sockaddr_in *sin;
612         struct sockaddr_un *sun;
613         char namebuf[INET_ADDRSTRLEN];
614 #ifdef INET6
615         struct sockaddr_in6 *sin6;
616         char namebuf6[INET6_ADDRSTRLEN];
617 #endif
618         u_int16_t port;
619
620         switch (af) {
621         case AF_INET:
622                 sin = nbuf->buf;
623                 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
624                     == NULL)
625                         return NULL;
626                 port = ntohs(sin->sin_port);
627                 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
628                     port & 0xff) < 0)
629                         return NULL;
630                 break;
631 #ifdef INET6
632         case AF_INET6:
633                 sin6 = nbuf->buf;
634                 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
635                     == NULL)
636                         return NULL;
637                 port = ntohs(sin6->sin6_port);
638                 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
639                     port & 0xff) < 0)
640                         return NULL;
641                 break;
642 #endif
643         case AF_LOCAL:
644                 sun = nbuf->buf;
645                 if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
646                     offsetof(struct sockaddr_un, sun_path)),
647                     sun->sun_path) < 0)
648                         return (NULL);
649                 break;
650         default:
651                 return NULL;
652         }
653
654         return ret;
655 }
656
657 struct netbuf *
658 __rpc_uaddr2taddr_af(int af, const char *uaddr)
659 {
660         struct netbuf *ret = NULL;
661         char *addrstr, *p;
662         unsigned port, portlo, porthi;
663         struct sockaddr_in *sin;
664 #ifdef INET6
665         struct sockaddr_in6 *sin6;
666 #endif
667         struct sockaddr_un *sun;
668
669         port = 0;
670         sin = NULL;
671         addrstr = strdup(uaddr);
672         if (addrstr == NULL)
673                 return NULL;
674
675         /*
676          * AF_LOCAL addresses are expected to be absolute
677          * pathnames, anything else will be AF_INET or AF_INET6.
678          */
679         if (*addrstr != '/') {
680                 p = strrchr(addrstr, '.');
681                 if (p == NULL)
682                         goto out;
683                 portlo = (unsigned)atoi(p + 1);
684                 *p = '\0';
685
686                 p = strrchr(addrstr, '.');
687                 if (p == NULL)
688                         goto out;
689                 porthi = (unsigned)atoi(p + 1);
690                 *p = '\0';
691                 port = (porthi << 8) | portlo;
692         }
693
694         ret = (struct netbuf *)malloc(sizeof *ret);
695         if (ret == NULL)
696                 goto out;
697         
698         switch (af) {
699         case AF_INET:
700                 sin = (struct sockaddr_in *)malloc(sizeof *sin);
701                 if (sin == NULL)
702                         goto out;
703                 memset(sin, 0, sizeof *sin);
704                 sin->sin_family = AF_INET;
705                 sin->sin_port = htons(port);
706                 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
707                         free(sin);
708                         free(ret);
709                         ret = NULL;
710                         goto out;
711                 }
712                 sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
713                 ret->buf = sin;
714                 break;
715 #ifdef INET6
716         case AF_INET6:
717                 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
718                 if (sin6 == NULL)
719                         goto out;
720                 memset(sin6, 0, sizeof *sin6);
721                 sin6->sin6_family = AF_INET6;
722                 sin6->sin6_port = htons(port);
723                 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
724                         free(sin6);
725                         free(ret);
726                         ret = NULL;
727                         goto out;
728                 }
729                 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
730                 ret->buf = sin6;
731                 break;
732 #endif
733         case AF_LOCAL:
734                 sun = (struct sockaddr_un *)malloc(sizeof *sun);
735                 if (sun == NULL)
736                         goto out;
737                 memset(sun, 0, sizeof *sun);
738                 sun->sun_family = AF_LOCAL;
739                 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
740                 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
741                 ret->buf = sun;
742                 break;
743         default:
744                 break;
745         }
746 out:
747         free(addrstr);
748         return ret;
749 }
750
751 int
752 __rpc_seman2socktype(int semantics)
753 {
754         switch (semantics) {
755         case NC_TPI_CLTS:
756                 return SOCK_DGRAM;
757         case NC_TPI_COTS_ORD:
758                 return SOCK_STREAM;
759         case NC_TPI_RAW:
760                 return SOCK_RAW;
761         default:
762                 break;
763         }
764
765         return -1;
766 }
767
768 int
769 __rpc_socktype2seman(int socktype)
770 {
771         switch (socktype) {
772         case SOCK_DGRAM:
773                 return NC_TPI_CLTS;
774         case SOCK_STREAM:
775                 return NC_TPI_COTS_ORD;
776         case SOCK_RAW:
777                 return NC_TPI_RAW;
778         default:
779                 break;
780         }
781
782         return -1;
783 }
784
785 /*
786  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
787  * Here, we compare the original server address to that of the RPC
788  * service we just received back from a call to rpcbind on the remote
789  * machine. If they are both "link local" or "site local", copy
790  * the scope id of the server address over to the service address.
791  */
792 int
793 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
794 {
795 #ifdef INET6
796         struct sockaddr *sa_new, *sa_svc;
797         struct sockaddr_in6 *sin6_new, *sin6_svc;
798
799         sa_svc = (struct sockaddr *)svc->buf;
800         sa_new = (struct sockaddr *)new->buf;
801
802         if (sa_new->sa_family == sa_svc->sa_family &&
803             sa_new->sa_family == AF_INET6) {
804                 sin6_new = (struct sockaddr_in6 *)new->buf;
805                 sin6_svc = (struct sockaddr_in6 *)svc->buf;
806
807                 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
808                      IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
809                     (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
810                      IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
811                         sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
812                 }
813         }
814 #endif
815         return 1;
816 }
817
818 int
819 __rpc_sockisbound(int fd)
820 {
821         struct sockaddr_storage ss;
822         socklen_t slen;
823
824         slen = sizeof (struct sockaddr_storage);
825         if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
826                 return 0;
827
828         switch (ss.ss_family) {
829                 case AF_INET:
830                         return (((struct sockaddr_in *)
831                             (void *)&ss)->sin_port != 0);
832 #ifdef INET6
833                 case AF_INET6:
834                         return (((struct sockaddr_in6 *)
835                             (void *)&ss)->sin6_port != 0);
836 #endif
837                 case AF_LOCAL:
838                         /* XXX check this */
839                         return (((struct sockaddr_un *)
840                             (void *)&ss)->sun_path[0] != '\0');
841                 default:
842                         break;
843         }
844
845         return 0;
846 }