1
2 /*
3 * Copyright (c) 2009, Sun Microsystems, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Sun Microsystems, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
32 * In addition, portions of such source code were derived from Berkeley
33 * 4.3 BSD under license from the Regents of the University of
34 * California.
35 */
36
37 #if defined(PORTMAP) || defined (_WIN32)
38 /*
39 * rpc_soc.c
40 *
41 * The backward compatibility routines for the earlier implementation
42 * of RPC, where the only transports supported were tcp/ip and udp/ip.
43 * Based on berkeley socket abstraction, now implemented on the top
44 * of TLI/Streams
45 */
46 #include <wintirpc.h>
47 //#include <pthread.h>
48 #include <reentrant.h>
49 #include <sys/types.h>
50 //#include <sys/socket.h>
51 #include <stdio.h>
52 #include <rpc/rpc.h>
53 #include <rpc/pmap_clnt.h>
54 #include <rpc/pmap_prot.h>
55 #include <rpc/nettype.h>
56 //#include <syslog.h>
57 //#include <netinet/in.h>
58 //#include <netdb.h>
59 #include <errno.h>
60 //#include <syslog.h>
61 #include <stdlib.h>
62 #include <string.h>
63 //#include <unistd.h>
64
65 #include "rpc_com.h"
66
67 extern mutex_t rpcsoc_lock;
68
69 static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
70 int *, u_int, u_int, char *);
71 static SVCXPRT *svc_com_create(SOCKET, u_int, u_int, char *);
72 static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
73
74 /* XXX */
75 #define IN4_LOCALHOST_STRING "127.0.0.1"
76 #define IN6_LOCALHOST_STRING "::1"
77
78 /*
79 * A common clnt create routine
80 */
81 static CLIENT *
clnt_com_create(raddr,prog,vers,sockp,sendsz,recvsz,tp)82 clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp)
83 struct sockaddr_in *raddr;
84 rpcprog_t prog;
85 rpcvers_t vers;
86 #ifndef __REACTOS__
87 SOCKET *sockp;
88 #else
89 int *sockp;
90 #endif
91 u_int sendsz;
92 u_int recvsz;
93 char *tp;
94 {
95 CLIENT *cl;
96 int madefd = FALSE;
97 SOCKET fd = *sockp;
98 struct netconfig *nconf;
99 struct netbuf bindaddr;
100
101 mutex_lock(&rpcsoc_lock);
102 if ((nconf = __rpc_getconfip(tp)) == NULL) {
103 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
104 mutex_unlock(&rpcsoc_lock);
105 return (NULL);
106 }
107 if (fd == RPC_ANYSOCK) {
108 fd = __rpc_nconf2fd(nconf);
109 if (fd == -1)
110 goto syserror;
111 madefd = TRUE;
112 }
113
114 if (raddr->sin_port == 0) {
115 u_int proto;
116 u_short sport;
117
118 mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */
119 proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
120 sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
121 proto);
122 if (sport == 0) {
123 goto err;
124 }
125 raddr->sin_port = htons(sport);
126 mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */
127 }
128
129 /* Transform sockaddr_in to netbuf */
130 bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in);
131 bindaddr.buf = raddr;
132
133 bindresvport(fd, NULL);
134 cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
135 sendsz, recvsz, NULL, NULL, NULL);
136 if (cl) {
137 if (madefd == TRUE) {
138 /*
139 * The fd should be closed while destroying the handle.
140 */
141 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
142 *sockp = fd;
143 }
144 (void) freenetconfigent(nconf);
145 mutex_unlock(&rpcsoc_lock);
146 return (cl);
147 }
148 goto err;
149
150 syserror:
151 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
152 rpc_createerr.cf_error.re_errno = errno;
153
154 err: if (madefd == TRUE)
155 (void)closesocket(fd);
156 (void) freenetconfigent(nconf);
157 mutex_unlock(&rpcsoc_lock);
158 return (NULL);
159 }
160
161 CLIENT *
clntudp_bufcreate(raddr,prog,vers,wait,sockp,sendsz,recvsz)162 clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz)
163 struct sockaddr_in *raddr;
164 u_long prog;
165 u_long vers;
166 struct timeval wait;
167 int *sockp;
168 u_int sendsz;
169 u_int recvsz;
170 {
171 CLIENT *cl;
172
173 cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
174 sendsz, recvsz, "udp");
175 if (cl == NULL) {
176 return (NULL);
177 }
178 (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
179 return (cl);
180 }
181
182 CLIENT *
clntudp_create(raddr,program,version,wait,sockp)183 clntudp_create(raddr, program, version, wait, sockp)
184 struct sockaddr_in *raddr;
185 u_long program;
186 u_long version;
187 struct timeval wait;
188 int *sockp;
189 {
190 return clntudp_bufcreate(raddr, program, version, wait, sockp, UDPMSGSIZE, UDPMSGSIZE);
191 }
192
193 CLIENT *
clnttcp_create(raddr,prog,vers,sockp,sendsz,recvsz)194 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
195 struct sockaddr_in *raddr;
196 u_long prog;
197 u_long vers;
198 int *sockp;
199 u_int sendsz;
200 u_int recvsz;
201 {
202 return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
203 sendsz, recvsz, "tcp");
204 }
205
206 /* IPv6 version of clnt*_*create */
207
208 #ifdef INET6_NOT_USED
209
210 CLIENT *
clntudp6_bufcreate(raddr,prog,vers,wait,sockp,sendsz,recvsz)211 clntudp6_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz)
212 struct sockaddr_in6 *raddr;
213 u_long prog;
214 u_long vers;
215 struct timeval wait;
216 int *sockp;
217 u_int sendsz;
218 u_int recvsz;
219 {
220 CLIENT *cl;
221
222 cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
223 sendsz, recvsz, "udp6");
224 if (cl == NULL) {
225 return (NULL);
226 }
227 (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
228 return (cl);
229 }
230
231 CLIENT *
clntudp6_create(raddr,program,version,wait,sockp)232 clntudp6_create(raddr, program, version, wait, sockp)
233 struct sockaddr_in6 *raddr;
234 u_long program;
235 u_long version;
236 struct timeval wait;
237 int *sockp;
238 {
239 return clntudp6_bufcreate(raddr, program, version, wait, sockp, UDPMSGSIZE, UDPMSGSIZE);
240 }
241
242 CLIENT *
clnttcp6_create(raddr,prog,vers,sockp,sendsz,recvsz)243 clnttcp6_create(raddr, prog, vers, sockp, sendsz, recvsz)
244 struct sockaddr_in6 *raddr;
245 u_long prog;
246 u_long vers;
247 int *sockp;
248 u_int sendsz;
249 u_int recvsz;
250 {
251 return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
252 sendsz, recvsz, "tcp6");
253 }
254
255 #endif
256
257 CLIENT *
clntraw_create(prog,vers)258 clntraw_create(prog, vers)
259 u_long prog;
260 u_long vers;
261 {
262 return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
263 }
264
265 /*
266 * A common server create routine
267 */
268 static SVCXPRT *
svc_com_create(fd,sendsize,recvsize,netid)269 svc_com_create(fd, sendsize, recvsize, netid)
270 SOCKET fd;
271 u_int sendsize;
272 u_int recvsize;
273 char *netid;
274 {
275 struct netconfig *nconf;
276 SVCXPRT *svc;
277 int madefd = FALSE;
278 int port;
279 struct sockaddr_in sin;
280
281 if ((nconf = __rpc_getconfip(netid)) == NULL) {
282 //(void) syslog(LOG_ERR, "Could not get %s transport", netid);
283 return (NULL);
284 }
285 if (fd == RPC_ANYSOCK) {
286 fd = __rpc_nconf2fd(nconf);
287 if (fd == -1) {
288 (void) freenetconfigent(nconf);
289 //(void) syslog(LOG_ERR,
290 //"svc%s_create: could not open connection", netid);
291 return (NULL);
292 }
293 madefd = TRUE;
294 }
295
296 memset(&sin, 0, sizeof sin);
297 sin.sin_family = AF_INET;
298 bindresvport(fd, &sin);
299 listen(fd, SOMAXCONN);
300 svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
301 (void) freenetconfigent(nconf);
302 if (svc == NULL) {
303 if (madefd)
304 (void)closesocket(fd);
305 return (NULL);
306 }
307 port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
308 svc->xp_port = ntohs((u_short)port);
309 return (svc);
310 }
311
312 SVCXPRT *
svctcp_create(fd,sendsize,recvsize)313 svctcp_create(fd, sendsize, recvsize)
314 #ifndef __REACTOS__
315 SOCKET fd;
316 #else
317 int fd;
318 #endif
319 u_int sendsize;
320 u_int recvsize;
321 {
322
323 return svc_com_create(fd, sendsize, recvsize, "tcp");
324 }
325
326
327
328 SVCXPRT *
svcudp_bufcreate(fd,sendsz,recvsz)329 svcudp_bufcreate(fd, sendsz, recvsz)
330 #ifndef __REACTOS__
331 SOCKET fd;
332 #else
333 int fd;
334 #endif
335 u_int sendsz, recvsz;
336 {
337
338 return svc_com_create(fd, sendsz, recvsz, "udp");
339 }
340
341
342
343 SVCXPRT *
svcfd_create(fd,sendsize,recvsize)344 svcfd_create(fd, sendsize, recvsize)
345 #ifndef __REACTOS__
346 SOCKET fd;
347 #else
348 int fd;
349 #endif
350 u_int sendsize;
351 u_int recvsize;
352 {
353
354 return svc_fd_create(fd, sendsize, recvsize);
355 }
356
357
358 SVCXPRT *
svcudp_create(fd)359 svcudp_create(fd)
360 #ifndef __REACTOS__
361 SOCKET fd;
362 #else
363 int fd;
364 #endif
365 {
366
367 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
368 }
369
370
371 SVCXPRT *
svcraw_create()372 svcraw_create()
373 {
374
375 return svc_raw_create();
376 }
377
378
379 /* IPV6 version */
380 #ifdef INET6_NOT_USED
381 SVCXPRT *
svcudp6_bufcreate(fd,sendsz,recvsz)382 svcudp6_bufcreate(fd, sendsz, recvsz)
383 int fd;
384 u_int sendsz, recvsz;
385 {
386 return svc_com_create(fd, sendsz, recvsz, "udp6");
387 }
388
389
390 SVCXPRT *
svctcp6_create(fd,sendsize,recvsize)391 svctcp6_create(fd, sendsize, recvsize)
392 int fd;
393 u_int sendsize;
394 u_int recvsize;
395 {
396 return svc_com_create(fd, sendsize, recvsize, "tcp6");
397 }
398
399
400 SVCXPRT *
svcudp6_create(fd)401 svcudp6_create(fd)
402 int fd;
403 {
404 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp6");
405 }
406 #endif
407
408 int
get_myaddress(addr)409 get_myaddress(addr)
410 struct sockaddr_in *addr;
411 {
412
413 memset((void *) addr, 0, sizeof(*addr));
414 addr->sin_family = AF_INET;
415 addr->sin_port = htons(PMAPPORT);
416 addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
417 return (0);
418 }
419
420 /*
421 * For connectionless "udp" transport. Obsoleted by rpc_call().
422 */
423 int
callrpc(host,prognum,versnum,procnum,inproc,in,outproc,out)424 callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
425 const char *host;
426 int prognum, versnum, procnum;
427 xdrproc_t inproc, outproc;
428 void *in, *out;
429 {
430
431 return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
432 (rpcproc_t)procnum, inproc, in, outproc, out, "udp");
433 }
434
435 /*
436 * For connectionless kind of transport. Obsoleted by rpc_reg()
437 */
438 int
registerrpc(prognum,versnum,procnum,progname,inproc,outproc)439 registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
440 int prognum, versnum, procnum;
441 char *(*progname)(char [UDPMSGSIZE]);
442 xdrproc_t inproc, outproc;
443 {
444
445 return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
446 (rpcproc_t)procnum, progname, inproc, outproc, "udp");
447 }
448
449 /*
450 * All the following clnt_broadcast stuff is convulated; it supports
451 * the earlier calling style of the callback function
452 */
453 extern thread_key_t clnt_broadcast_key;
454
455 /*
456 * Need to translate the netbuf address into sockaddr_in address.
457 * Dont care about netid here.
458 */
459 /* ARGSUSED */
460 static bool_t
rpc_wrap_bcast(resultp,addr,nconf)461 rpc_wrap_bcast(resultp, addr, nconf)
462 char *resultp; /* results of the call */
463 struct netbuf *addr; /* address of the guy who responded */
464 struct netconfig *nconf; /* Netconf of the transport */
465 {
466 resultproc_t clnt_broadcast_result;
467
468 if (strcmp(nconf->nc_netid, "udp"))
469 return (FALSE);
470 clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
471 return (*clnt_broadcast_result)(resultp,
472 (struct sockaddr_in *)addr->buf);
473 }
474
475 /*
476 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
477 */
478 enum clnt_stat
clnt_broadcast(prog,vers,proc,xargs,argsp,xresults,resultsp,eachresult)479 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
480 u_long prog; /* program number */
481 u_long vers; /* version number */
482 u_long proc; /* procedure number */
483 xdrproc_t xargs; /* xdr routine for args */
484 void *argsp; /* pointer to args */
485 xdrproc_t xresults; /* xdr routine for results */
486 void *resultsp; /* pointer to results */
487 resultproc_t eachresult; /* call with each result obtained */
488 {
489 extern mutex_t tsd_lock;
490
491 if (clnt_broadcast_key == -1) {
492 mutex_lock(&tsd_lock);
493 if (clnt_broadcast_key == -1)
494 thr_keycreate(&clnt_broadcast_key, free);
495 mutex_unlock(&tsd_lock);
496 }
497 thr_setspecific(clnt_broadcast_key, (void *) eachresult);
498 return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
499 (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
500 (resultproc_t) rpc_wrap_bcast, "udp");
501 }
502
503 #ifndef _WIN32
504 /*
505 * Create the client des authentication object. Obsoleted by
506 * authdes_seccreate().
507 */
508 AUTH *
authdes_create(servername,window,syncaddr,ckey)509 authdes_create(servername, window, syncaddr, ckey)
510 char *servername; /* network name of server */
511 u_int window; /* time to live */
512 struct sockaddr *syncaddr; /* optional hostaddr to sync with */
513 des_block *ckey; /* optional conversation key to use */
514 {
515 AUTH *dummy;
516 AUTH *nauth;
517 char hostname[NI_MAXHOST];
518
519 if (syncaddr) {
520 /*
521 * Change addr to hostname, because that is the way
522 * new interface takes it.
523 */
524 if (getnameinfo(syncaddr, sizeof(syncaddr), hostname,
525 sizeof hostname, NULL, 0, 0) != 0)
526 goto fallback;
527
528 nauth = authdes_seccreate(servername, window, hostname, ckey);
529 return (nauth);
530 }
531 fallback:
532 dummy = authdes_seccreate(servername, window, NULL, ckey);
533 return (dummy);
534 }
535 #endif
536
537 /*
538 * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
539 */
540 CLIENT *
clntunix_create(raddr,prog,vers,sockp,sendsz,recvsz)541 clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz)
542 struct sockaddr_un *raddr;
543 u_long prog;
544 u_long vers;
545 #ifndef __REACTOS__
546 SOCKET *sockp;
547 #else
548 int *sockp;
549 #endif
550 u_int sendsz;
551 u_int recvsz;
552 {
553 struct netbuf *svcaddr;
554 struct netconfig *nconf;
555 CLIENT *cl;
556 int len;
557
558 cl = NULL;
559 nconf = NULL;
560 svcaddr = NULL;
561 if (((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
562 ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
563 if (svcaddr != NULL)
564 free(svcaddr);
565 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
566 rpc_createerr.cf_error.re_errno = errno;
567 return(cl);
568 }
569 if (*sockp == SOCKET_ERROR) {
570 *sockp = socket(AF_UNIX, SOCK_STREAM, 0);
571 len = SUN_LEN(raddr);
572 if ((*sockp == INVALID_SOCKET) || (connect(*sockp,
573 (struct sockaddr *)raddr, len) == SOCKET_ERROR)) {
574 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
575 rpc_createerr.cf_error.re_errno = errno;
576 if (*sockp != INVALID_SOCKET)
577 (void)closesocket(*sockp);
578 goto done;
579 }
580 }
581 svcaddr->buf = raddr;
582 svcaddr->len = sizeof(raddr);
583 svcaddr->maxlen = sizeof (struct sockaddr_un);
584 cl = clnt_vc_create(*sockp, svcaddr, prog,
585 vers, sendsz, recvsz, NULL, NULL, NULL);
586 done:
587 free(svcaddr->buf);
588 free(svcaddr);
589 return(cl);
590 }
591
592 /*
593 * Creates, registers, and returns a (rpc) unix based transporter.
594 * Obsoleted by svc_vc_create().
595 */
596 SVCXPRT *
svcunix_create(sock,sendsize,recvsize,path)597 svcunix_create(sock, sendsize, recvsize, path)
598 #ifndef __REACTOS__
599 SOCKET sock;
600 #else
601 int sock;
602 #endif
603 u_int sendsize;
604 u_int recvsize;
605 char *path;
606 {
607 struct netconfig *nconf;
608 void *localhandle;
609 struct sockaddr_un sun;
610 struct sockaddr *sa;
611 struct t_bind taddr;
612 SVCXPRT *xprt;
613 int addrlen;
614
615 xprt = (SVCXPRT *)NULL;
616 localhandle = setnetconfig();
617 while ((nconf = getnetconfig(localhandle)) != NULL) {
618 if (nconf->nc_protofmly != NULL &&
619 strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
620 break;
621 }
622 if (nconf == NULL)
623 return(xprt);
624
625 if ((sock = __rpc_nconf2fd(nconf)) == SOCKET_ERROR)
626 goto done;
627
628 memset(&sun, 0, sizeof sun);
629 sun.sun_family = AF_UNIX;
630 strncpy(sun.sun_path, path, sizeof(sun.sun_path));
631 addrlen = sizeof(struct sockaddr_un);
632 sa = (struct sockaddr *)&sun;
633
634 if (bind(sock, sa, addrlen) == SOCKET_ERROR)
635 goto done;
636
637 taddr.addr.len = taddr.addr.maxlen = addrlen;
638 taddr.addr.buf = malloc(addrlen);
639 if (taddr.addr.buf == NULL)
640 goto done;
641 memcpy(taddr.addr.buf, sa, addrlen);
642
643 if (nconf->nc_semantics != NC_TPI_CLTS) {
644 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
645 free(taddr.addr.buf);
646 goto done;
647 }
648 }
649
650 xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
651
652 done:
653 endnetconfig(localhandle);
654 return(xprt);
655 }
656
657 /*
658 * Like svunix_create(), except the routine takes any *open* UNIX file
659 * descriptor as its first input. Obsoleted by svc_fd_create();
660 */
661 SVCXPRT *
svcunixfd_create(fd,sendsize,recvsize)662 svcunixfd_create(fd, sendsize, recvsize)
663 #ifndef __REACTOS__
664 SOCKET fd;
665 #else
666 int fd;
667 #endif
668 u_int sendsize;
669 u_int recvsize;
670 {
671 return (svc_fd_create(fd, sendsize, recvsize));
672 }
673
674 #endif /* PORTMAP */
675