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