rpc_generic.c revision 1.14 1 /* $NetBSD: rpc_generic.c,v 1.14 2003/09/09 00:22:17 itojun Exp $ */
2
3 /*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31 /*
32 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 */
34
35 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
36
37 /*
38 * rpc_generic.c, Miscl routines for RPC.
39 *
40 */
41
42 #include "namespace.h"
43 #include "reentrant.h"
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/un.h>
48 #include <sys/resource.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <rpc/rpc.h>
52 #include <assert.h>
53 #include <ctype.h>
54 #include <stdio.h>
55 #include <netdb.h>
56 #include <netconfig.h>
57 #include <malloc.h>
58 #include <string.h>
59 #include <syslog.h>
60 #include <rpc/nettype.h>
61 #include "rpc_internal.h"
62
63 struct handle {
64 NCONF_HANDLE *nhandle;
65 int nflag; /* Whether NETPATH or NETCONFIG */
66 int nettype;
67 };
68
69 static const struct _rpcnettype {
70 const char *name;
71 const int type;
72 } _rpctypelist[] = {
73 { "netpath", _RPC_NETPATH },
74 { "visible", _RPC_VISIBLE },
75 { "circuit_v", _RPC_CIRCUIT_V },
76 { "datagram_v", _RPC_DATAGRAM_V },
77 { "circuit_n", _RPC_CIRCUIT_N },
78 { "datagram_n", _RPC_DATAGRAM_N },
79 { "tcp", _RPC_TCP },
80 { "udp", _RPC_UDP },
81 { 0, _RPC_NONE }
82 };
83
84 struct netid_af {
85 const char *netid;
86 int af;
87 int protocol;
88 };
89
90 static const struct netid_af na_cvt[] = {
91 { "udp", AF_INET, IPPROTO_UDP },
92 { "tcp", AF_INET, IPPROTO_TCP },
93 #ifdef INET6
94 { "udp6", AF_INET6, IPPROTO_UDP },
95 { "tcp6", AF_INET6, IPPROTO_TCP },
96 #endif
97 { "local", AF_LOCAL, 0 }
98 };
99
100 #if 0
101 static char *strlocase __P((char *));
102 #endif
103 static int getnettype __P((const char *));
104
105 /*
106 * Cache the result of getrlimit(), so we don't have to do an
107 * expensive call every time.
108 */
109 int
110 __rpc_dtbsize()
111 {
112 static int tbsize;
113 struct rlimit rl;
114
115 if (tbsize) {
116 return (tbsize);
117 }
118 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
119 return (tbsize = (int)rl.rlim_max);
120 }
121 /*
122 * Something wrong. I'll try to save face by returning a
123 * pessimistic number.
124 */
125 return (32);
126 }
127
128
129 /*
130 * Find the appropriate buffer size
131 */
132 u_int
133 /*ARGSUSED*/
134 __rpc_get_t_size(af, proto, size)
135 int af, proto;
136 int size; /* Size requested */
137 {
138 int maxsize, defsize;
139
140 maxsize = 256 * 1024; /* XXX */
141 switch (proto) {
142 case IPPROTO_TCP:
143 defsize = 64 * 1024; /* XXX */
144 break;
145 case IPPROTO_UDP:
146 defsize = UDPMSGSIZE;
147 break;
148 default:
149 defsize = RPC_MAXDATASIZE;
150 break;
151 }
152 if (size == 0)
153 return defsize;
154
155 /* Check whether the value is within the upper max limit */
156 return (size > maxsize ? (u_int)maxsize : (u_int)size);
157 }
158
159 /*
160 * Find the appropriate address buffer size
161 */
162 u_int
163 __rpc_get_a_size(af)
164 int af;
165 {
166 switch (af) {
167 case AF_INET:
168 return sizeof (struct sockaddr_in);
169 #ifdef INET6
170 case AF_INET6:
171 return sizeof (struct sockaddr_in6);
172 #endif
173 case AF_LOCAL:
174 return sizeof (struct sockaddr_un);
175 default:
176 break;
177 }
178 return ((u_int)RPC_MAXADDRSIZE);
179 }
180
181 #if 0
182 static char *
183 strlocase(p)
184 char *p;
185 {
186 char *t = p;
187
188 _DIAGASSERT(p != NULL);
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(nettype)
203 const char *nettype;
204 {
205 int i;
206
207 if ((nettype == NULL) || (nettype[0] == NULL)) {
208 return (_RPC_NETPATH); /* Default */
209 }
210
211 #if 0
212 nettype = strlocase(nettype);
213 #endif
214 for (i = 0; _rpctypelist[i].name; i++)
215 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
216 return (_rpctypelist[i].type);
217 }
218 return (_rpctypelist[i].type);
219 }
220
221 /*
222 * For the given nettype (tcp or udp only), return the first structure found.
223 * This should be freed by calling freenetconfigent()
224 */
225
226 #ifdef _REENTRANT
227 static thread_key_t tcp_key, udp_key;
228 static once_t __rpc_getconfigp_once = ONCE_INITIALIZER;
229
230 static void
231 __rpc_getconfigp_setup(void)
232 {
233
234 thr_keycreate(&tcp_key, free);
235 thr_keycreate(&udp_key, free);
236 }
237 #endif
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 #ifdef _REENTRANT
250 extern int __isthreaded;
251
252 if (__isthreaded == 0) {
253 netid_udp = netid_udp_main;
254 netid_tcp = netid_tcp_main;
255 } else {
256 thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup);
257 netid_tcp = thr_getspecific(tcp_key);
258 netid_udp = thr_getspecific(udp_key);
259 }
260 #else
261 netid_udp = netid_udp_main;
262 netid_tcp = netid_tcp_main;
263 #endif
264
265 _DIAGASSERT(nettype != NULL);
266
267 if (!netid_udp && !netid_tcp) {
268 struct netconfig *nconf;
269 void *confighandle;
270
271 if (!(confighandle = setnetconfig())) {
272 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
273 return (NULL);
274 }
275 while ((nconf = getnetconfig(confighandle)) != NULL) {
276 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
277 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
278 netid_tcp = strdup(nconf->nc_netid);
279 #ifdef _REENTRANT
280 if (__isthreaded == 0)
281 netid_tcp_main = netid_tcp;
282 else
283 thr_setspecific(tcp_key,
284 (void *) netid_tcp);
285 #else
286 netid_tcp_main = netid_tcp;
287 #endif
288 } else
289 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
290 netid_udp = strdup(nconf->nc_netid);
291 #ifdef _REENTRANT
292 if (__isthreaded == 0)
293 netid_udp_main = netid_udp;
294 else
295 thr_setspecific(udp_key,
296 (void *) netid_udp);
297 #else
298 netid_udp_main = netid_udp;
299 #endif
300 }
301 }
302 }
303 endnetconfig(confighandle);
304 }
305 if (strcmp(nettype, "udp") == 0)
306 netid = netid_udp;
307 else if (strcmp(nettype, "tcp") == 0)
308 netid = netid_tcp;
309 else {
310 return (NULL);
311 }
312 if ((netid == NULL) || (netid[0] == NULL)) {
313 return (NULL);
314 }
315 dummy = getnetconfigent(netid);
316 return (dummy);
317 }
318
319 /*
320 * Returns the type of the nettype, which should then be used with
321 * __rpc_getconf().
322 */
323 void *
324 __rpc_setconf(nettype)
325 const char *nettype;
326 {
327 struct handle *handle;
328
329 /* nettype may be NULL; getnettype() supports that */
330
331 handle = (struct handle *) malloc(sizeof (struct handle));
332 if (handle == NULL) {
333 return (NULL);
334 }
335 switch (handle->nettype = getnettype(nettype)) {
336 case _RPC_NETPATH:
337 case _RPC_CIRCUIT_N:
338 case _RPC_DATAGRAM_N:
339 if (!(handle->nhandle = setnetpath())) {
340 free(handle);
341 return (NULL);
342 }
343 handle->nflag = TRUE;
344 break;
345 case _RPC_VISIBLE:
346 case _RPC_CIRCUIT_V:
347 case _RPC_DATAGRAM_V:
348 case _RPC_TCP:
349 case _RPC_UDP:
350 if (!(handle->nhandle = setnetconfig())) {
351 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
352 free(handle);
353 return (NULL);
354 }
355 handle->nflag = FALSE;
356 break;
357 default:
358 return (NULL);
359 }
360
361 return (handle);
362 }
363
364 /*
365 * Returns the next netconfig struct for the given "net" type.
366 * __rpc_setconf() should have been called previously.
367 */
368 struct netconfig *
369 __rpc_getconf(vhandle)
370 void *vhandle;
371 {
372 struct handle *handle;
373 struct netconfig *nconf;
374
375 handle = (struct handle *)vhandle;
376 if (handle == NULL) {
377 return (NULL);
378 }
379 for (;;) {
380 if (handle->nflag)
381 nconf = getnetpath(handle->nhandle);
382 else
383 nconf = getnetconfig(handle->nhandle);
384 if (nconf == NULL)
385 break;
386 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
387 (nconf->nc_semantics != NC_TPI_COTS) &&
388 (nconf->nc_semantics != NC_TPI_COTS_ORD))
389 continue;
390 switch (handle->nettype) {
391 case _RPC_VISIBLE:
392 if (!(nconf->nc_flag & NC_VISIBLE))
393 continue;
394 /* FALLTHROUGH */
395 case _RPC_NETPATH: /* Be happy */
396 break;
397 case _RPC_CIRCUIT_V:
398 if (!(nconf->nc_flag & NC_VISIBLE))
399 continue;
400 /* FALLTHROUGH */
401 case _RPC_CIRCUIT_N:
402 if ((nconf->nc_semantics != NC_TPI_COTS) &&
403 (nconf->nc_semantics != NC_TPI_COTS_ORD))
404 continue;
405 break;
406 case _RPC_DATAGRAM_V:
407 if (!(nconf->nc_flag & NC_VISIBLE))
408 continue;
409 /* FALLTHROUGH */
410 case _RPC_DATAGRAM_N:
411 if (nconf->nc_semantics != NC_TPI_CLTS)
412 continue;
413 break;
414 case _RPC_TCP:
415 if (((nconf->nc_semantics != NC_TPI_COTS) &&
416 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
417 (strcmp(nconf->nc_protofmly, NC_INET)
418 #ifdef INET6
419 && strcmp(nconf->nc_protofmly, NC_INET6))
420 #else
421 )
422 #endif
423 ||
424 strcmp(nconf->nc_proto, NC_TCP))
425 continue;
426 break;
427 case _RPC_UDP:
428 if ((nconf->nc_semantics != NC_TPI_CLTS) ||
429 (strcmp(nconf->nc_protofmly, NC_INET)
430 #ifdef INET6
431 && strcmp(nconf->nc_protofmly, NC_INET6))
432 #else
433 )
434 #endif
435 ||
436 strcmp(nconf->nc_proto, NC_UDP))
437 continue;
438 break;
439 }
440 break;
441 }
442 return (nconf);
443 }
444
445 void
446 __rpc_endconf(vhandle)
447 void * vhandle;
448 {
449 struct handle *handle;
450
451 handle = (struct handle *) vhandle;
452 if (handle == NULL) {
453 return;
454 }
455 if (handle->nflag) {
456 endnetpath(handle->nhandle);
457 } else {
458 endnetconfig(handle->nhandle);
459 }
460 free(handle);
461 }
462
463 /*
464 * Used to ping the NULL procedure for clnt handle.
465 * Returns NULL if fails, else a non-NULL pointer.
466 */
467 void *
468 rpc_nullproc(clnt)
469 CLIENT *clnt;
470 {
471 struct timeval TIMEOUT = {25, 0};
472
473 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
474 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
475 return (NULL);
476 }
477 return ((void *) clnt);
478 }
479
480 /*
481 * Try all possible transports until
482 * one succeeds in finding the netconf for the given fd.
483 */
484 struct netconfig *
485 __rpcgettp(fd)
486 int fd;
487 {
488 const char *netid;
489 struct __rpc_sockinfo si;
490
491 if (!__rpc_fd2sockinfo(fd, &si))
492 return NULL;
493
494 if (!__rpc_sockinfo2netid(&si, &netid))
495 return NULL;
496
497 /*LINTED const castaway*/
498 return getnetconfigent((char *)netid);
499 }
500
501 int
502 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
503 {
504 socklen_t len;
505 int type, proto;
506 struct sockaddr_storage ss;
507
508 _DIAGASSERT(sip != NULL);
509
510 len = sizeof ss;
511 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
512 return 0;
513 sip->si_alen = len;
514
515 len = sizeof type;
516 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
517 return 0;
518
519 /* XXX */
520 if (ss.ss_family != AF_LOCAL) {
521 if (type == SOCK_STREAM)
522 proto = IPPROTO_TCP;
523 else if (type == SOCK_DGRAM)
524 proto = IPPROTO_UDP;
525 else
526 return 0;
527 } else
528 proto = 0;
529
530 sip->si_af = ss.ss_family;
531 sip->si_proto = proto;
532 sip->si_socktype = type;
533
534 return 1;
535 }
536
537 /*
538 * Linear search, but the number of entries is small.
539 */
540 int
541 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
542 {
543 size_t i;
544
545 _DIAGASSERT(nconf != NULL);
546 _DIAGASSERT(sip != NULL);
547
548 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
549 if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
550 sip->si_af = na_cvt[i].af;
551 sip->si_proto = na_cvt[i].protocol;
552 sip->si_socktype =
553 __rpc_seman2socktype((int)nconf->nc_semantics);
554 if (sip->si_socktype == -1)
555 return 0;
556 sip->si_alen = __rpc_get_a_size(sip->si_af);
557 return 1;
558 }
559
560 return 0;
561 }
562
563 int
564 __rpc_nconf2fd(const struct netconfig *nconf)
565 {
566 struct __rpc_sockinfo si;
567
568 _DIAGASSERT(nconf != NULL);
569
570 if (!__rpc_nconf2sockinfo(nconf, &si))
571 return 0;
572
573 return socket(si.si_af, si.si_socktype, si.si_proto);
574 }
575
576 int
577 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
578 {
579 size_t i;
580
581 _DIAGASSERT(sip != NULL);
582 /* netid may be NULL */
583
584 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
585 if (na_cvt[i].af == sip->si_af &&
586 na_cvt[i].protocol == sip->si_proto) {
587 if (netid)
588 *netid = na_cvt[i].netid;
589 return 1;
590 }
591
592 return 0;
593 }
594
595 char *
596 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
597 {
598 struct __rpc_sockinfo si;
599
600 _DIAGASSERT(nconf != NULL);
601 _DIAGASSERT(nbuf != NULL);
602
603 if (!__rpc_nconf2sockinfo(nconf, &si))
604 return NULL;
605 return __rpc_taddr2uaddr_af(si.si_af, nbuf);
606 }
607
608 struct netbuf *
609 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
610 {
611 struct __rpc_sockinfo si;
612
613 _DIAGASSERT(nconf != NULL);
614 _DIAGASSERT(uaddr != NULL);
615
616 if (!__rpc_nconf2sockinfo(nconf, &si))
617 return NULL;
618 return __rpc_uaddr2taddr_af(si.si_af, uaddr);
619 }
620
621 char *
622 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
623 {
624 char *ret;
625 struct sockaddr_in *sinp;
626 struct sockaddr_un *sun;
627 char namebuf[INET_ADDRSTRLEN];
628 #ifdef INET6
629 struct sockaddr_in6 *sin6;
630 char namebuf6[INET6_ADDRSTRLEN];
631 #endif
632 u_int16_t port;
633
634 _DIAGASSERT(nbuf != NULL);
635
636 switch (af) {
637 case AF_INET:
638 sinp = nbuf->buf;
639 if (inet_ntop(af, &sinp->sin_addr, namebuf, sizeof namebuf)
640 == NULL)
641 return NULL;
642 port = ntohs(sinp->sin_port);
643 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
644 port & 0xff) < 0)
645 return NULL;
646 break;
647 #ifdef INET6
648 case AF_INET6:
649 sin6 = nbuf->buf;
650 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
651 == NULL)
652 return NULL;
653 port = ntohs(sin6->sin6_port);
654 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
655 port & 0xff) < 0)
656 return NULL;
657 break;
658 #endif
659 case AF_LOCAL:
660 sun = nbuf->buf;
661 sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
662 ret = strdup(sun->sun_path);
663 break;
664 default:
665 return NULL;
666 }
667
668 return ret;
669 }
670
671 struct netbuf *
672 __rpc_uaddr2taddr_af(int af, const char *uaddr)
673 {
674 struct netbuf *ret = NULL;
675 char *addrstr, *p;
676 unsigned port, portlo, porthi;
677 struct sockaddr_in *sinp;
678 #ifdef INET6
679 struct sockaddr_in6 *sin6;
680 #endif
681 struct sockaddr_un *sun;
682
683 _DIAGASSERT(uaddr != NULL);
684
685 addrstr = strdup(uaddr);
686 if (addrstr == NULL)
687 return NULL;
688
689 /*
690 * AF_LOCAL addresses are expected to be absolute
691 * pathnames, anything else will be AF_INET or AF_INET6.
692 */
693 if (*addrstr != '/') {
694 p = strrchr(addrstr, '.');
695 if (p == NULL)
696 goto out;
697 portlo = (unsigned)atoi(p + 1);
698 *p = '\0';
699
700 p = strrchr(addrstr, '.');
701 if (p == NULL)
702 goto out;
703 porthi = (unsigned)atoi(p + 1);
704 *p = '\0';
705 port = (porthi << 8) | portlo;
706 }
707
708 ret = (struct netbuf *)malloc(sizeof *ret);
709 if (ret == NULL)
710 goto out;
711
712 switch (af) {
713 case AF_INET:
714 sinp = (struct sockaddr_in *)malloc(sizeof *sinp);
715 if (sinp == NULL)
716 goto out;
717 memset(sinp, 0, sizeof *sinp);
718 sinp->sin_family = AF_INET;
719 sinp->sin_port = htons(port);
720 if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) {
721 free(sinp);
722 free(ret);
723 ret = NULL;
724 goto out;
725 }
726 sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp;
727 ret->buf = sinp;
728 break;
729 #ifdef INET6
730 case AF_INET6:
731 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
732 if (sin6 == NULL)
733 goto out;
734 memset(sin6, 0, sizeof *sin6);
735 sin6->sin6_family = AF_INET6;
736 sin6->sin6_port = htons(port);
737 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
738 free(sin6);
739 free(ret);
740 ret = NULL;
741 goto out;
742 }
743 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
744 ret->buf = sin6;
745 break;
746 #endif
747 case AF_LOCAL:
748 sun = (struct sockaddr_un *)malloc(sizeof *sun);
749 if (sun == NULL)
750 goto out;
751 memset(sun, 0, sizeof *sun);
752 sun->sun_family = AF_LOCAL;
753 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
754 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
755 ret->buf = sun;
756 break;
757 default:
758 break;
759 }
760 out:
761 free(addrstr);
762 return ret;
763 }
764
765 int
766 __rpc_seman2socktype(int semantics)
767 {
768 switch (semantics) {
769 case NC_TPI_CLTS:
770 return SOCK_DGRAM;
771 case NC_TPI_COTS_ORD:
772 return SOCK_STREAM;
773 case NC_TPI_RAW:
774 return SOCK_RAW;
775 default:
776 break;
777 }
778
779 return -1;
780 }
781
782 int
783 __rpc_socktype2seman(int socktype)
784 {
785 switch (socktype) {
786 case SOCK_DGRAM:
787 return NC_TPI_CLTS;
788 case SOCK_STREAM:
789 return NC_TPI_COTS_ORD;
790 case SOCK_RAW:
791 return NC_TPI_RAW;
792 default:
793 break;
794 }
795
796 return -1;
797 }
798
799 /*
800 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
801 * Here, we compare the original server address to that of the RPC
802 * service we just received back from a call to rpcbind on the remote
803 * machine. If they are both "link local" or "site local", copy
804 * the scope id of the server address over to the service address.
805 */
806 int
807 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
808 {
809 #ifdef INET6
810 struct sockaddr *sa_new, *sa_svc;
811 struct sockaddr_in6 *sin6_new, *sin6_svc;
812
813 _DIAGASSERT(new != NULL);
814 _DIAGASSERT(svc != NULL);
815
816 sa_svc = (struct sockaddr *)svc->buf;
817 sa_new = (struct sockaddr *)new->buf;
818
819 if (sa_new->sa_family == sa_svc->sa_family &&
820 sa_new->sa_family == AF_INET6) {
821 sin6_new = (struct sockaddr_in6 *)new->buf;
822 sin6_svc = (struct sockaddr_in6 *)svc->buf;
823
824 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
825 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
826 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
827 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
828 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
829 }
830 }
831 #endif
832 return 1;
833 }
834
835 int
836 __rpc_sockisbound(int fd)
837 {
838 struct sockaddr_storage ss;
839 socklen_t slen;
840
841 slen = sizeof (struct sockaddr_storage);
842 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
843 return 0;
844
845 switch (ss.ss_family) {
846 case AF_INET:
847 return (((struct sockaddr_in *)
848 (void *)&ss)->sin_port != 0);
849 #ifdef INET6
850 case AF_INET6:
851 return (((struct sockaddr_in6 *)
852 (void *)&ss)->sin6_port != 0);
853 #endif
854 case AF_LOCAL:
855 /* XXX check this */
856 return (((struct sockaddr_un *)
857 (void *)&ss)->sun_path[0] != '\0');
858 default:
859 break;
860 }
861
862 return 0;
863 }
864
865 /* $OpenBSD: ip_id.c,v 1.6 2002/03/15 18:19:52 millert Exp $ */
866
867 /*
868 * Copyright 1998 Niels Provos <provos (at) citi.umich.edu>
869 * All rights reserved.
870 *
871 * Theo de Raadt <deraadt (at) openbsd.org> came up with the idea of using
872 * such a mathematical system to generate more random (yet non-repeating)
873 * ids to solve the resolver/named problem. But Niels designed the
874 * actual system based on the constraints.
875 *
876 * Redistribution and use in source and binary forms, with or without
877 * modification, are permitted provided that the following conditions
878 * are met:
879 * 1. Redistributions of source code must retain the above copyright
880 * notice, this list of conditions and the following disclaimer.
881 * 2. Redistributions in binary form must reproduce the above copyright
882 * notice, this list of conditions and the following disclaimer in the
883 * documentation and/or other materials provided with the distribution.
884 * 3. All advertising materials mentioning features or use of this software
885 * must display the following acknowledgement:
886 * This product includes software developed by Niels Provos.
887 * 4. The name of the author may not be used to endorse or promote products
888 * derived from this software without specific prior written permission.
889 *
890 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
891 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
892 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
893 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
894 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
895 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
896 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
897 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
898 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
899 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
900 */
901
902 /*
903 * seed = random 31bit
904 * n = prime, g0 = generator to n,
905 * j = random so that gcd(j,n-1) == 1
906 * g = g0^j mod n will be a generator again.
907 *
908 * X[0] = random seed.
909 * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
910 * with a = 7^(even random) mod m,
911 * b = random with gcd(b,m) == 1
912 * m = 1836660096 and a maximal period of m-1.
913 *
914 * The transaction id is determined by:
915 * id[n] = seed xor (g^X[n] mod n)
916 *
917 * Effectivly the id is restricted to the lower 31 bits, thus
918 * yielding two different cycles by toggling the msb on and off.
919 * This avoids reuse issues caused by reseeding.
920 */
921
922 #define RU_OUT 180 /* Time after wich will be reseeded */
923 #define RU_MAX 1000000000 /* Uniq cycle, avoid blackjack prediction */
924 #define RU_GEN 2 /* Starting generator */
925 #define RU_N 2147483629 /* RU_N-1 = 2^2*3^2*59652323 */
926 #define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */
927 #define RU_M 1836660096 /* RU_M = 2^7*3^15 - don't change */
928
929 #define PFAC_N 3
930 const static u_int32_t pfacts[PFAC_N] = {
931 2,
932 3,
933 59652323
934 };
935
936 static u_int32_t ru_x;
937 static u_int32_t ru_seed, ru_seed2;
938 static u_int32_t ru_a, ru_b;
939 static u_int32_t ru_g;
940 static u_int32_t ru_counter = 0;
941 static u_int32_t ru_msb = 0;
942 static long ru_reseed;
943
944 static u_int32_t pmod(u_int32_t, u_int32_t, u_int32_t);
945 static void initid(void);
946
947 /*
948 * Do a fast modular exponation, returned value will be in the range
949 * of 0 - (mod-1)
950 */
951 static u_int32_t
952 pmod(u_int32_t gen, u_int32_t exp, u_int32_t mod)
953 {
954 u_int64_t s, t, u;
955
956 s = 1;
957 t = gen;
958 u = exp;
959
960 while (u) {
961 if (u & 1)
962 s = (s * t) % mod;
963 u >>= 1;
964 t = (t * t) % mod;
965 }
966 return ((u_int32_t)s & 0xffffffff);
967 }
968
969 /*
970 * Initalizes the seed and chooses a suitable generator. Also toggles
971 * the msb flag. The msb flag is used to generate two distinct
972 * cycles of random numbers and thus avoiding reuse of ids.
973 *
974 * This function is called from id_randomid() when needed, an
975 * application does not have to worry about it.
976 */
977 static void
978 initid(void)
979 {
980 u_int32_t j, i;
981 int noprime = 1;
982 struct timeval tv;
983
984 ru_x = arc4random() % RU_M;
985
986 /* 31 bits of random seed */
987 ru_seed = arc4random() & INT32_MAX;
988 ru_seed2 = arc4random() & INT32_MAX;
989
990 /* Determine the LCG we use */
991 ru_b = arc4random() | 1;
992 ru_a = pmod(RU_AGEN, arc4random() & (~1U), RU_M);
993 while (ru_b % 3 == 0)
994 ru_b += 2;
995
996 j = arc4random() % RU_N;
997
998 /*
999 * Do a fast gcd(j,RU_N-1), so we can find a j with
1000 * gcd(j, RU_N-1) == 1, giving a new generator for
1001 * RU_GEN^j mod RU_N
1002 */
1003 while (noprime) {
1004 for (i = 0; i < PFAC_N; i++)
1005 if (j % pfacts[i] == 0)
1006 break;
1007
1008 if (i >= PFAC_N)
1009 noprime = 0;
1010 else
1011 j = (j + 1) % RU_N;
1012 }
1013
1014 ru_g = pmod(RU_GEN, j, RU_N);
1015 ru_counter = 0;
1016
1017 gettimeofday(&tv, NULL);
1018 ru_reseed = tv.tv_sec + RU_OUT;
1019 ru_msb = ru_msb ? 0 : 0x80000000;
1020 }
1021
1022 u_int32_t
1023 __rpc_getxid(void)
1024 {
1025 int i, n;
1026 u_int32_t tmp;
1027 struct timeval tv;
1028
1029 gettimeofday(&tv, NULL);
1030 if (ru_counter >= RU_MAX || tv.tv_sec > ru_reseed)
1031 initid();
1032
1033 tmp = arc4random();
1034
1035 /* Skip a random number of ids */
1036 n = tmp & 0x3; tmp = tmp >> 2;
1037 if (ru_counter + n >= RU_MAX)
1038 initid();
1039
1040 for (i = 0; i <= n; i++) {
1041 /* Linear Congruential Generator */
1042 ru_x = (ru_a * ru_x + ru_b) % RU_M;
1043 }
1044
1045 ru_counter += i;
1046
1047 return (ru_seed ^ pmod(ru_g, ru_seed2 ^ ru_x,RU_N)) | ru_msb;
1048 }
1049