[LIBTIRPC] Fix CVE-2017-8779 by backporting its fix
[reactos.git] / dll / 3rdparty / libtirpc / src / rpc_generic.c
1 /*
2 * Copyright (c) 2009, Sun Microsystems, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /*
29 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
30 */
31
32 //#include <sys/cdefs.h>
33
34 /*
35 * rpc_generic.c, Miscl routines for RPC.
36 *
37 */
38 #include <wintirpc.h>
39 //#include <pthread.h>
40 #include <reentrant.h>
41 #include <sys/types.h>
42 //#include <sys/param.h>
43 //#include <sys/socket.h>
44 //#include <sys/time.h>
45 //#include <sys/un.h>
46 //#include <sys/resource.h>
47 //#include <netinet/in.h>
48 //#include <arpa/inet.h>
49 #include <rpc/rpc.h>
50 //#include <ctype.h>
51 //#include <stddef.h>
52 #include <stdio.h>
53 //#include <netdb.h>
54 #include <netconfig.h>
55 #include <stdlib.h>
56 #include <string.h>
57 //#include <syslog.h>
58 #include <rpc/nettype.h>
59 #include "rpc_com.h"
60
61 struct handle {
62 NCONF_HANDLE *nhandle;
63 int nflag; /* Whether NETPATH or NETCONFIG */
64 int nettype;
65 };
66
67 static const struct _rpcnettype {
68 const char *name;
69 const int type;
70 } _rpctypelist[] = {
71 { "netpath", _RPC_NETPATH },
72 { "visible", _RPC_VISIBLE },
73 { "circuit_v", _RPC_CIRCUIT_V },
74 { "datagram_v", _RPC_DATAGRAM_V },
75 { "circuit_n", _RPC_CIRCUIT_N },
76 { "datagram_n", _RPC_DATAGRAM_N },
77 { "tcp", _RPC_TCP },
78 { "udp", _RPC_UDP },
79 { 0, _RPC_NONE }
80 };
81
82 struct netid_af {
83 const char *netid;
84 ADDRESS_FAMILY af;
85 int protocol;
86 };
87
88 static const struct netid_af na_cvt[] = {
89 { "udp", AF_INET, IPPROTO_UDP },
90 { "tcp", AF_INET, IPPROTO_TCP },
91 #ifdef INET6
92 { "udp6", AF_INET6, IPPROTO_UDP },
93 { "tcp6", AF_INET6, IPPROTO_TCP },
94 #endif
95 #ifdef AF_LOCAL
96 { "local", AF_LOCAL, 0 }
97 #endif
98 };
99
100 #if 0
101 static char *strlocase(char *);
102 #endif
103 static int getnettype(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 #ifdef _WIN32
113 return (WINSOCK_HANDLE_HASH_SIZE);
114 #else
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 #endif
131 }
132
133
134 /*
135 * Find the appropriate buffer size
136 */
137 u_int
138 /*ARGSUSED*/
139 __rpc_get_t_size(af, proto, size)
140 int af, proto;
141 int size; /* Size requested */
142 {
143 int maxsize, defsize;
144
145 maxsize = 256 * 1024; /* XXX */
146 switch (proto) {
147 case IPPROTO_TCP:
148 defsize = 1024 * 1024; /* XXX */
149 break;
150 case IPPROTO_UDP:
151 defsize = UDPMSGSIZE;
152 break;
153 default:
154 defsize = RPC_MAXDATASIZE;
155 break;
156 }
157 if (size == 0)
158 return defsize;
159 #if 1
160 /* cbodley- give us the size we ask for, or we'll get fragmented! */
161 return (u_int)size;
162 #else
163 /* Check whether the value is within the upper max limit */
164 return (size > maxsize ? (u_int)maxsize : (u_int)size);
165 #endif
166 }
167
168 /*
169 * Find the appropriate address buffer size
170 */
171 u_int
172 __rpc_get_a_size(af)
173 int af;
174 {
175 switch (af) {
176 case AF_INET:
177 return sizeof (struct sockaddr_in);
178 #ifdef INET6
179 case AF_INET6:
180 return sizeof (struct sockaddr_in6);
181 #endif
182 #ifdef AF_LOCAL
183 case AF_LOCAL:
184 return sizeof (struct sockaddr_un);
185 #endif
186 default:
187 break;
188 }
189 return ((u_int)RPC_MAXADDRSIZE);
190 }
191
192 #if 0
193 static char *
194 strlocase(p)
195 char *p;
196 {
197 char *t = p;
198
199 for (; *p; p++)
200 if (isupper(*p))
201 *p = tolower(*p);
202 return (t);
203 }
204 #endif
205
206 /*
207 * Returns the type of the network as defined in <rpc/nettype.h>
208 * If nettype is NULL, it defaults to NETPATH.
209 */
210 static int
211 getnettype(nettype)
212 const char *nettype;
213 {
214 int i;
215
216 if ((nettype == NULL) || (nettype[0] == 0)) {
217 return (_RPC_NETPATH); /* Default */
218 }
219
220 #if 0
221 nettype = strlocase(nettype);
222 #endif
223 for (i = 0; _rpctypelist[i].name; i++)
224 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
225 return (_rpctypelist[i].type);
226 }
227 return (_rpctypelist[i].type);
228 }
229
230 /*
231 * For the given nettype (tcp or udp only), return the first structure found.
232 * This should be freed by calling freenetconfigent()
233 */
234 struct netconfig *
235 __rpc_getconfip(nettype)
236 const char *nettype;
237 {
238 char *netid;
239 char *netid_tcp = (char *) NULL;
240 char *netid_udp = (char *) NULL;
241 struct netconfig *dummy;
242 extern thread_key_t tcp_key, udp_key;
243 extern mutex_t tsd_lock;
244
245 if (tcp_key == -1) {
246 mutex_lock(&tsd_lock);
247 if (tcp_key == -1)
248 tcp_key = TlsAlloc(); //thr_keycreate(&tcp_key, free);
249 mutex_unlock(&tsd_lock);
250 }
251 netid_tcp = (char *)thr_getspecific(tcp_key);
252 if (udp_key == -1) {
253 mutex_lock(&tsd_lock);
254 if (udp_key == -1)
255 udp_key = TlsAlloc(); //thr_keycreate(&udp_key, free);
256 mutex_unlock(&tsd_lock);
257 }
258 netid_udp = (char *)thr_getspecific(udp_key);
259 if (!netid_udp && !netid_tcp) {
260 struct netconfig *nconf;
261 void *confighandle;
262
263 if (!(confighandle = setnetconfig())) {
264 //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
265 return (NULL);
266 }
267 while ((nconf = getnetconfig(confighandle)) != NULL) {
268 if (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
269 strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
270 if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
271 netid_tcp == NULL) {
272 netid_tcp = strdup(nconf->nc_netid);
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 thr_setspecific(udp_key,
280 (void *) netid_udp);
281 }
282 }
283 }
284 endnetconfig(confighandle);
285 }
286 if (strcmp(nettype, "udp") == 0)
287 netid = netid_udp;
288 else if (strcmp(nettype, "tcp") == 0)
289 netid = netid_tcp;
290 else {
291 return (NULL);
292 }
293 if ((netid == NULL) || (netid[0] == 0)) {
294 return (NULL);
295 }
296 dummy = getnetconfigent(netid);
297 return (dummy);
298 }
299
300 /*
301 * Returns the type of the nettype, which should then be used with
302 * __rpc_getconf().
303 */
304 void *
305 __rpc_setconf(nettype)
306 const char *nettype;
307 {
308 struct handle *handle;
309
310 handle = (struct handle *) malloc(sizeof (struct handle));
311 if (handle == NULL) {
312 return (NULL);
313 }
314 switch (handle->nettype = getnettype(nettype)) {
315 case _RPC_NETPATH:
316 case _RPC_CIRCUIT_N:
317 case _RPC_DATAGRAM_N:
318 if (!(handle->nhandle = setnetpath())) {
319 free(handle);
320 return (NULL);
321 }
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 free(handle);
332 return (NULL);
333 }
334 handle->nflag = FALSE;
335 break;
336 default:
337 return (NULL);
338 }
339
340 return (handle);
341 }
342
343 /*
344 * Returns the next netconfig struct for the given "net" type.
345 * __rpc_setconf() should have been called previously.
346 */
347 struct netconfig *
348 __rpc_getconf(vhandle)
349 void *vhandle;
350 {
351 struct handle *handle;
352 struct netconfig *nconf;
353
354 handle = (struct handle *)vhandle;
355 if (handle == NULL) {
356 return (NULL);
357 }
358 for (;;) {
359 if (handle->nflag)
360 nconf = getnetpath(handle->nhandle);
361 else
362 nconf = getnetconfig(handle->nhandle);
363 if (nconf == NULL)
364 break;
365 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
366 (nconf->nc_semantics != NC_TPI_COTS) &&
367 (nconf->nc_semantics != NC_TPI_COTS_ORD))
368 continue;
369 switch (handle->nettype) {
370 case _RPC_VISIBLE:
371 if (!(nconf->nc_flag & NC_VISIBLE))
372 continue;
373 /* FALLTHROUGH */
374 case _RPC_NETPATH: /* Be happy */
375 break;
376 case _RPC_CIRCUIT_V:
377 if (!(nconf->nc_flag & NC_VISIBLE))
378 continue;
379 /* FALLTHROUGH */
380 case _RPC_CIRCUIT_N:
381 if ((nconf->nc_semantics != NC_TPI_COTS) &&
382 (nconf->nc_semantics != NC_TPI_COTS_ORD))
383 continue;
384 break;
385 case _RPC_DATAGRAM_V:
386 if (!(nconf->nc_flag & NC_VISIBLE))
387 continue;
388 /* FALLTHROUGH */
389 case _RPC_DATAGRAM_N:
390 if (nconf->nc_semantics != NC_TPI_CLTS)
391 continue;
392 break;
393 case _RPC_TCP:
394 if (((nconf->nc_semantics != NC_TPI_COTS) &&
395 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
396 (strcmp(nconf->nc_protofmly, NC_INET)
397 #ifdef INET6
398 && strcmp(nconf->nc_protofmly, NC_INET6))
399 #else
400 )
401 #endif
402 ||
403 strcmp(nconf->nc_proto, NC_TCP))
404 continue;
405 break;
406 case _RPC_UDP:
407 if ((nconf->nc_semantics != NC_TPI_CLTS) ||
408 (strcmp(nconf->nc_protofmly, NC_INET)
409 #ifdef INET6
410 && strcmp(nconf->nc_protofmly, NC_INET6))
411 #else
412 )
413 #endif
414 ||
415 strcmp(nconf->nc_proto, NC_UDP))
416 continue;
417 break;
418 }
419 break;
420 }
421 return (nconf);
422 }
423
424 void
425 __rpc_endconf(vhandle)
426 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(clnt)
448 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(fd)
465 SOCKET fd;
466 {
467 const char *netid;
468 struct __rpc_sockinfo si;
469
470 if (!__rpc_fd2sockinfo(fd, &si))
471 return NULL;
472
473 if (!__rpc_sockinfo2netid(&si, &netid))
474 return NULL;
475
476 /*LINTED const castaway*/
477 return getnetconfigent((char *)netid);
478 }
479
480 int
481 __rpc_fd2sockinfo(SOCKET fd, struct __rpc_sockinfo *sip)
482 {
483 socklen_t len;
484 int type, proto;
485 struct sockaddr_storage ss;
486
487 #ifdef _WIN32
488 WSAPROTOCOL_INFO proto_info;
489 int proto_info_size = sizeof(proto_info);
490 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&proto_info, &proto_info_size) == SOCKET_ERROR) {
491 #ifndef __REACTOS__
492 int err = WSAGetLastError();
493 #endif
494 return 0;
495 }
496 len = proto_info.iMaxSockAddr;
497 ss.ss_family = (ADDRESS_FAMILY)proto_info.iAddressFamily;
498 #else
499 len = sizeof ss;
500 if (getsockname(fd, (struct sockaddr *)&ss, &len) == SOCKET_ERROR) {
501 return 0;
502 }
503 #endif
504 sip->si_alen = len;
505
506 len = sizeof type;
507 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&type, &len) == SOCKET_ERROR) {
508 #ifndef __REACTOS__
509 int err = WSAGetLastError();
510 #endif
511 return 0;
512 }
513
514 /* XXX */
515 #ifdef AF_LOCAL
516 if (ss.ss_family != AF_LOCAL) {
517 #endif
518 if (type == SOCK_STREAM)
519 proto = IPPROTO_TCP;
520 else if (type == SOCK_DGRAM)
521 proto = IPPROTO_UDP;
522 else
523 return 0;
524 #ifdef AF_LOCAL
525 } else
526 proto = 0;
527 #endif
528
529 sip->si_af = ss.ss_family;
530 sip->si_proto = proto;
531 sip->si_socktype = type;
532
533 return 1;
534 }
535
536 /*
537 * Linear search, but the number of entries is small.
538 */
539 int
540 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
541 {
542 int i;
543
544 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
545 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
546 strcmp(nconf->nc_netid, "unix") == 0 &&
547 strcmp(na_cvt[i].netid, "local") == 0)) {
548 sip->si_af = na_cvt[i].af;
549 sip->si_proto = na_cvt[i].protocol;
550 sip->si_socktype =
551 __rpc_seman2socktype((int)nconf->nc_semantics);
552 if (sip->si_socktype == -1)
553 return 0;
554 sip->si_alen = __rpc_get_a_size(sip->si_af);
555 return 1;
556 }
557
558 return 0;
559 }
560
561 SOCKET
562 __rpc_nconf2fd(const struct netconfig *nconf)
563 {
564 struct __rpc_sockinfo si;
565 SOCKET fd;
566
567 if (!__rpc_nconf2sockinfo(nconf, &si))
568 return 0;
569
570 if ((fd = socket(si.si_af, si.si_socktype, si.si_proto)) != INVALID_SOCKET &&
571 si.si_af == AF_INET6) {
572 int val = 1;
573
574 setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (const char *)&val, sizeof(val));
575 }
576 return fd;
577 }
578
579 int
580 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
581 {
582 int i;
583 struct netconfig *nconf;
584
585 nconf = getnetconfigent("local");
586
587 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
588 if (na_cvt[i].af == sip->si_af &&
589 na_cvt[i].protocol == sip->si_proto) {
590 if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
591 if (netid)
592 *netid = "unix";
593 } else {
594 if (netid)
595 *netid = na_cvt[i].netid;
596 }
597 if (nconf != NULL)
598 freenetconfigent(nconf);
599 return 1;
600 }
601 }
602 if (nconf != NULL)
603 freenetconfigent(nconf);
604
605 return 0;
606 }
607
608 char *
609 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
610 {
611 struct __rpc_sockinfo si;
612
613 if (!__rpc_nconf2sockinfo(nconf, &si))
614 return NULL;
615 return __rpc_taddr2uaddr_af(si.si_af, nbuf);
616 }
617
618 struct netbuf *
619 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
620 {
621 struct __rpc_sockinfo si;
622
623 if (!__rpc_nconf2sockinfo(nconf, &si))
624 return NULL;
625 return __rpc_uaddr2taddr_af(si.si_af, uaddr);
626 }
627
628 void freeuaddr(char *uaddr)
629 {
630 free(uaddr);
631 }
632
633 void freenetbuf(struct netbuf *nbuf)
634 {
635 if (nbuf) {
636 free(nbuf->buf);
637 free(nbuf);
638 }
639 }
640
641 #ifdef __REACTOS__
642 PCSTR
643 WSAAPI
644 inet_ntop(INT af, PVOID src, PSTR dst, size_t cnt)
645 {
646 struct in_addr in;
647 char *text_addr;
648
649 if (af == AF_INET) {
650 memcpy(&in.s_addr, src, sizeof(in.s_addr));
651 text_addr = inet_ntoa(in);
652 if (text_addr && dst) {
653 strncpy(dst, text_addr, cnt);
654 return dst;
655 }
656 }
657
658 return 0;
659 }
660 #endif
661
662 char *
663 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
664 {
665 char *ret;
666 struct sockaddr_in *sin;
667 #ifdef AF_LOCAL
668 struct sockaddr_un *sun;
669 #endif
670 char namebuf[INET_ADDRSTRLEN];
671 #ifdef INET6
672 struct sockaddr_in6 *sin6;
673 char namebuf6[INET6_ADDRSTRLEN];
674 #endif
675 u_int16_t port;
676
677 if (nbuf->len <= 0)
678 return NULL;
679
680 switch (af) {
681 case AF_INET:
682 #ifdef __REACTOS__ // CVE-2017-8779
683 if (nbuf->len < sizeof(*sin)) {
684 return NULL;
685 }
686 #endif
687 sin = nbuf->buf;
688 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
689 == NULL)
690 return NULL;
691 port = ntohs(sin->sin_port);
692 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
693 port & 0xff) < 0)
694 return NULL;
695 break;
696 #ifdef INET6
697 case AF_INET6:
698 #ifdef __REACTOS__ // CVE-2017-8779
699 if (nbuf->len < sizeof(*sin6)) {
700 return NULL;
701 }
702 #endif
703 sin6 = nbuf->buf;
704 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
705 == NULL)
706 return NULL;
707 port = ntohs(sin6->sin6_port);
708 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
709 port & 0xff) < 0)
710 return NULL;
711 break;
712 #endif
713 #ifdef AF_LOCAL
714 case AF_LOCAL:
715 sun = nbuf->buf;
716 /* if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
717 offsetof(struct sockaddr_un, sun_path)),
718 sun->sun_path) < 0)*/
719 if (asprintf(&ret, "%.*s", (int)(sizeof(*sun) -
720 offsetof(struct sockaddr_un, sun_path)),
721 sun->sun_path) < 0)
722
723 return (NULL);
724 break;
725 #endif
726 default:
727 return NULL;
728 }
729
730 return ret;
731 }
732
733 struct netbuf *
734 __rpc_uaddr2taddr_af(int af, const char *uaddr)
735 {
736 struct netbuf *ret = NULL;
737 char *addrstr, *p;
738 unsigned short port, portlo, porthi;
739 struct sockaddr_in *sin;
740 #ifdef INET6
741 struct sockaddr_in6 *sin6;
742 #endif
743 #ifdef AF_LOCAL
744 struct sockaddr_un *sun;
745 #endif
746
747 port = 0;
748 sin = NULL;
749 #ifdef __REACTOS__ // CVE-2017-8779
750 if (uaddr == NULL)
751 return NULL;
752 #endif
753 addrstr = strdup(uaddr);
754 if (addrstr == NULL)
755 return NULL;
756
757 /*
758 * AF_LOCAL addresses are expected to be absolute
759 * pathnames, anything else will be AF_INET or AF_INET6.
760 */
761 if (*addrstr != '/') {
762 p = strrchr(addrstr, '.');
763 if (p == NULL)
764 goto out;
765 portlo = (unsigned)atoi(p + 1);
766 *p = '\0';
767
768 p = strrchr(addrstr, '.');
769 if (p == NULL)
770 goto out;
771 porthi = (unsigned)atoi(p + 1);
772 *p = '\0';
773 port = (porthi << 8) | portlo;
774 }
775
776 ret = (struct netbuf *)malloc(sizeof *ret);
777 if (ret == NULL)
778 goto out;
779
780 switch (af) {
781 case AF_INET:
782 sin = (struct sockaddr_in *)malloc(sizeof *sin);
783 if (sin == NULL)
784 goto out;
785 memset(sin, 0, sizeof *sin);
786 sin->sin_family = AF_INET;
787 sin->sin_port = htons(port);
788 #ifndef __REACTOS__
789 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
790 #else
791 sin->sin_addr.S_un.S_addr = inet_addr(addrstr);
792 if (sin->sin_addr.S_un.S_addr == INADDR_NONE) {
793 #endif
794 free(sin);
795 free(ret);
796 ret = NULL;
797 goto out;
798 }
799 ret->maxlen = ret->len = sizeof *sin;
800 ret->buf = sin;
801 break;
802 #ifdef INET6
803 case AF_INET6:
804 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
805 if (sin6 == NULL)
806 goto out;
807 memset(sin6, 0, sizeof *sin6);
808 sin6->sin6_family = AF_INET6;
809 sin6->sin6_port = htons(port);
810 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
811 free(sin6);
812 free(ret);
813 ret = NULL;
814 goto out;
815 }
816 ret->maxlen = ret->len = sizeof *sin6;
817 ret->buf = sin6;
818 break;
819 #endif
820 #ifdef AF_LOCAL
821 case AF_LOCAL:
822 sun = (struct sockaddr_un *)malloc(sizeof *sun);
823 if (sun == NULL)
824 goto out;
825 memset(sun, 0, sizeof *sun);
826 sun->sun_family = AF_LOCAL;
827 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
828 ret->len = SUN_LEN(sun);
829 ret->maxlen = sizeof(struct sockaddr_un);
830 ret->buf = sun;
831 break;
832 #endif
833 default:
834 break;
835 }
836 out:
837 free(addrstr);
838 return ret;
839 }
840
841 int
842 __rpc_seman2socktype(int semantics)
843 {
844 switch (semantics) {
845 case NC_TPI_CLTS:
846 return SOCK_DGRAM;
847 case NC_TPI_COTS_ORD:
848 return SOCK_STREAM;
849 case NC_TPI_RAW:
850 return SOCK_RAW;
851 default:
852 break;
853 }
854
855 return -1;
856 }
857
858 int
859 __rpc_socktype2seman(int socktype)
860 {
861 switch (socktype) {
862 case SOCK_DGRAM:
863 return NC_TPI_CLTS;
864 case SOCK_STREAM:
865 return NC_TPI_COTS_ORD;
866 case SOCK_RAW:
867 return NC_TPI_RAW;
868 default:
869 break;
870 }
871
872 return -1;
873 }
874
875 /*
876 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
877 * Here, we compare the original server address to that of the RPC
878 * service we just received back from a call to rpcbind on the remote
879 * machine. If they are both "link local" or "site local", copy
880 * the scope id of the server address over to the service address.
881 */
882 int
883 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
884 {
885 #ifdef INET6
886 struct sockaddr *sa_new, *sa_svc;
887 struct sockaddr_in6 *sin6_new, *sin6_svc;
888
889 sa_svc = (struct sockaddr *)svc->buf;
890 sa_new = (struct sockaddr *)new->buf;
891
892 if (sa_new->sa_family == sa_svc->sa_family &&
893 sa_new->sa_family == AF_INET6) {
894 sin6_new = (struct sockaddr_in6 *)new->buf;
895 sin6_svc = (struct sockaddr_in6 *)svc->buf;
896
897 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
898 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
899 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
900 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
901 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
902 }
903 }
904 #endif
905 return 1;
906 }
907
908 int
909 __rpc_sockisbound(SOCKET fd)
910 {
911 struct sockaddr_storage ss;
912 union {
913 struct sockaddr_in sin;
914 struct sockaddr_in6 sin6;
915 #ifdef AF_LOCAL
916 struct sockaddr_un usin;
917 #endif
918 } u_addr;
919 socklen_t slen;
920
921 slen = sizeof (struct sockaddr_storage);
922 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR)
923 return 0;
924
925 switch (ss.ss_family) {
926 case AF_INET:
927 memcpy(&u_addr.sin, &ss, sizeof(u_addr.sin));
928 return (u_addr.sin.sin_port != 0);
929 #ifdef INET6
930 case AF_INET6:
931 memcpy(&u_addr.sin6, &ss, sizeof(u_addr.sin6));
932 return (u_addr.sin6.sin6_port != 0);
933 #endif
934 #ifdef AF_LOCAL
935 case AF_LOCAL:
936 /* XXX check this */
937 memcpy(&u_addr.usin, &ss, sizeof(u_addr.usin));
938 return (u_addr.usin.sun_path[0] != 0);
939 #endif
940 default:
941 break;
942 }
943
944 return 0;
945 }
946
947 /*
948 * Helper function to set up a netbuf
949 */
950 struct netbuf *
951 __rpc_set_netbuf(struct netbuf *nb, const void *ptr, size_t len)
952 {
953 if (nb->len != len) {
954 if (nb->len)
955 mem_free(nb->buf, nb->len);
956 nb->buf = mem_alloc(len);
957 if (nb->buf == NULL)
958 return NULL;
959
960 nb->maxlen = nb->len = len;
961 }
962 memcpy(nb->buf, ptr, len);
963 return nb;
964 }