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