xref: /dflybsd-src/lib/libc/rpc/rpc_soc.c (revision 1682d0d9b38b9dfa89cf2360c842c2ebf748e352)
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  * @(#)rpc_soc.c	1.17	94/04/24 SMI; 1.41 89/05/02 Copyr 1988 Sun Micro
29  * $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $
30  * $FreeBSD: src/lib/libc/rpc/rpc_soc.c,v 1.15 2006/02/27 22:10:59 deischen Exp $
31  * $DragonFly$
32  */
33 
34 /*
35  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
36  * In addition, portions of such source code were derived from Berkeley
37  * 4.3 BSD under license from the Regents of the University of
38  * California.
39  */
40 
41 #ifdef PORTMAP
42 /*
43  * rpc_soc.c
44  *
45  * The backward compatibility routines for the earlier implementation
46  * of RPC, where the only transports supported were tcp/ip and udp/ip.
47  * Based on berkeley socket abstraction, now implemented on the top
48  * of TLI/Streams
49  */
50 
51 #include "namespace.h"
52 #include "reentrant.h"
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <stdio.h>
56 #include <rpc/rpc.h>
57 #include <rpc/pmap_clnt.h>
58 #include <rpc/pmap_prot.h>
59 #include <rpc/nettype.h>
60 #include <syslog.h>
61 #include <netinet/in.h>
62 #include <netdb.h>
63 #include <errno.h>
64 #include <syslog.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68 #include "un-namespace.h"
69 
70 #include "rpc_com.h"
71 #include "mt_misc.h"
72 
73 static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
74     int *, u_int, u_int, char *);
75 static SVCXPRT *svc_com_create(int, u_int, u_int, char *);
76 static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
77 
78 /* XXX */
79 #define IN4_LOCALHOST_STRING    "127.0.0.1"
80 #define IN6_LOCALHOST_STRING    "::1"
81 
82 /*
83  * A common clnt create routine
84  */
85 static CLIENT *
86 clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
87 		int *sockp, u_int sendsz, u_int recvsz, char *tp)
88 {
89 	CLIENT *cl;
90 	int madefd = FALSE;
91 	int fd = *sockp;
92 	struct netconfig *nconf;
93 	struct netbuf bindaddr;
94 
95 	mutex_lock(&rpcsoc_lock);
96 	if ((nconf = __rpc_getconfip(tp)) == NULL) {
97 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
98 		mutex_unlock(&rpcsoc_lock);
99 		return (NULL);
100 	}
101 	if (fd == RPC_ANYSOCK) {
102 		fd = __rpc_nconf2fd(nconf);
103 		if (fd == -1)
104 			goto syserror;
105 		madefd = TRUE;
106 	}
107 
108 	if (raddr->sin_port == 0) {
109 		u_int proto;
110 		u_short sport;
111 
112 		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
113 		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
114 		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
115 		    proto);
116 		if (sport == 0) {
117 			goto err;
118 		}
119 		raddr->sin_port = htons(sport);
120 		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
121 	}
122 
123 	/* Transform sockaddr_in to netbuf */
124 	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
125 	bindaddr.buf = raddr;
126 
127 	bindresvport(fd, NULL);
128 	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
129 				sendsz, recvsz);
130 	if (cl) {
131 		if (madefd == TRUE) {
132 			/*
133 			 * The fd should be closed while destroying the handle.
134 			 */
135 			CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
136 			*sockp = fd;
137 		}
138 		freenetconfigent(nconf);
139 		mutex_unlock(&rpcsoc_lock);
140 		return (cl);
141 	}
142 	goto err;
143 
144 syserror:
145 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
146 	rpc_createerr.cf_error.re_errno = errno;
147 
148 err:	if (madefd == TRUE)
149 		_close(fd);
150 	freenetconfigent(nconf);
151 	mutex_unlock(&rpcsoc_lock);
152 	return (NULL);
153 }
154 
155 CLIENT *
156 clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers,
157 		  struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
158 {
159 	CLIENT *cl;
160 
161 	cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
162 	    sendsz, recvsz, "udp");
163 	if (cl == NULL) {
164 		return (NULL);
165 	}
166 	CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
167 	return (cl);
168 }
169 
170 CLIENT *
171 clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
172 	       struct timeval wait, int *sockp)
173 {
174 
175 	return clntudp_bufcreate(raddr, program, version, wait, sockp,
176 					UDPMSGSIZE, UDPMSGSIZE);
177 }
178 
179 CLIENT *
180 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
181 	       u_int sendsz, u_int recvsz)
182 {
183 
184 	return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
185 	    sendsz, recvsz, "tcp");
186 }
187 
188 CLIENT *
189 clntraw_create(u_long prog, u_long vers)
190 {
191 
192 	return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
193 }
194 
195 /*
196  * A common server create routine
197  */
198 static SVCXPRT *
199 svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
200 {
201 	struct netconfig *nconf;
202 	SVCXPRT *svc;
203 	int madefd = FALSE;
204 	int port;
205 	struct sockaddr_in sin;
206 
207 	if ((nconf = __rpc_getconfip(netid)) == NULL) {
208 		syslog(LOG_ERR, "Could not get %s transport", netid);
209 		return (NULL);
210 	}
211 	if (fd == RPC_ANYSOCK) {
212 		fd = __rpc_nconf2fd(nconf);
213 		if (fd == -1) {
214 			freenetconfigent(nconf);
215 			syslog(LOG_ERR,
216 			"svc%s_create: could not open connection", netid);
217 			return (NULL);
218 		}
219 		madefd = TRUE;
220 	}
221 
222 	memset(&sin, 0, sizeof sin);
223 	sin.sin_family = AF_INET;
224 	bindresvport(fd, &sin);
225 	_listen(fd, SOMAXCONN);
226 	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
227 	freenetconfigent(nconf);
228 	if (svc == NULL) {
229 		if (madefd)
230 			_close(fd);
231 		return (NULL);
232 	}
233 	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
234 	svc->xp_port = ntohs(port);
235 	return (svc);
236 }
237 
238 SVCXPRT *
239 svctcp_create(int fd, u_int sendsize, u_int recvsize)
240 {
241 
242 	return svc_com_create(fd, sendsize, recvsize, "tcp");
243 }
244 
245 SVCXPRT *
246 svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz)
247 {
248 
249 	return svc_com_create(fd, sendsz, recvsz, "udp");
250 }
251 
252 SVCXPRT *
253 svcfd_create(int fd, u_int sendsize, u_int recvsize)
254 {
255 
256 	return svc_fd_create(fd, sendsize, recvsize);
257 }
258 
259 
260 SVCXPRT *
261 svcudp_create(int fd)
262 {
263 
264 	return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
265 }
266 
267 SVCXPRT *
268 svcraw_create(void)
269 {
270 
271 	return svc_raw_create();
272 }
273 
274 int
275 get_myaddress(struct sockaddr_in *addr)
276 {
277 
278 	memset((void *) addr, 0, sizeof(*addr));
279 	addr->sin_family = AF_INET;
280 	addr->sin_port = htons(PMAPPORT);
281 	addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
282 	return (0);
283 }
284 
285 /*
286  * For connectionless "udp" transport. Obsoleted by rpc_call().
287  */
288 int
289 callrpc(const char *host, int prognum, int versnum, int procnum,
290 	xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
291 {
292 
293 	return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
294 	    (rpcproc_t)procnum, inproc, in, outproc, out, "udp");
295 }
296 
297 /*
298  * For connectionless kind of transport. Obsoleted by rpc_reg()
299  */
300 int
301 registerrpc(int prognum, int versnum, int procnum, char *(*progname)(char *),
302 	    xdrproc_t inproc, xdrproc_t outproc)
303 {
304 
305 	return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
306 	    (rpcproc_t)procnum, progname, inproc, outproc, "udp");
307 }
308 
309 /*
310  * All the following clnt_broadcast stuff is convulated; it supports
311  * the earlier calling style of the callback function
312  */
313 static thread_key_t	clnt_broadcast_key;
314 static resultproc_t	clnt_broadcast_result_main;
315 
316 /*
317  * Need to translate the netbuf address into sockaddr_in address.
318  * Dont care about netid here.
319  */
320 /* ARGSUSED */
321 static bool_t
322 rpc_wrap_bcast(char *resultp,		/* results of the call */
323 	       struct netbuf *addr,	/* address of the guy who responded */
324 	       struct netconfig *nconf) /* Netconf of the transport */
325 {
326 	resultproc_t clnt_broadcast_result;
327 
328 	if (strcmp(nconf->nc_netid, "udp"))
329 		return (FALSE);
330 	if (thr_main())
331 		clnt_broadcast_result = clnt_broadcast_result_main;
332 	else
333 		clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
334 	return (*clnt_broadcast_result)(resultp,
335 				(struct sockaddr_in *)addr->buf);
336 }
337 
338 /*
339  * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
340  */
341 enum clnt_stat
342 clnt_broadcast(u_long		prog,		/* program number */
343 	       u_long		vers,		/* version number */
344 	       u_long		proc,		/* procedure number */
345 	       xdrproc_t	xargs,		/* xdr routine for args */
346 	       void	       *argsp,		/* pointer to args */
347 	       xdrproc_t	xresults,	/* xdr routine for results */
348 	       void	       *resultsp,	/* pointer to results */
349 	       resultproc_t	eachresult)	/* call with each result obtained */
350 {
351 
352 	if (thr_main())
353 		clnt_broadcast_result_main = eachresult;
354 	else {
355 		if (clnt_broadcast_key == 0) {
356 			mutex_lock(&tsd_lock);
357 			if (clnt_broadcast_key == 0)
358 				thr_keycreate(&clnt_broadcast_key, free);
359 			mutex_unlock(&tsd_lock);
360 		}
361 		thr_setspecific(clnt_broadcast_key, (void *) eachresult);
362 	}
363 	return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
364 	    (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
365 	    (resultproc_t) rpc_wrap_bcast, "udp");
366 }
367 
368 /*
369  * Create the client des authentication object. Obsoleted by
370  * authdes_seccreate().
371  */
372 AUTH *
373 authdes_create(char *servername,	 /* network name of server */
374 	       u_int window,		 /* time to live */
375 	       struct sockaddr *syncaddr,/* optional hostaddr to sync with */
376 	       des_block *ckey)		 /* optional conversation key to use */
377 {
378 	AUTH *dummy;
379 	AUTH *nauth;
380 	char hostname[NI_MAXHOST];
381 
382 	if (syncaddr) {
383 		/*
384 		 * Change addr to hostname, because that is the way
385 		 * new interface takes it.
386 		 */
387 		if (getnameinfo(syncaddr, syncaddr->sa_len, hostname,
388 		    sizeof hostname, NULL, 0, 0) != 0)
389 			goto fallback;
390 
391 		nauth = authdes_seccreate(servername, window, hostname, ckey);
392 		return (nauth);
393 	}
394 fallback:
395 	dummy = authdes_seccreate(servername, window, NULL, ckey);
396 	return (dummy);
397 }
398 
399 /*
400  * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
401  */
402 CLIENT *
403 clntunix_create(struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp,
404 		u_int sendsz, u_int recvsz)
405 {
406 	struct netbuf *svcaddr;
407 	struct netconfig *nconf;
408 	CLIENT *cl;
409 	int len;
410 
411 	cl = NULL;
412 	nconf = NULL;
413 	svcaddr = NULL;
414 	if ((raddr->sun_len == 0) ||
415 	   ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
416 	   ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
417 		if (svcaddr != NULL)
418 			free(svcaddr);
419 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
420 		rpc_createerr.cf_error.re_errno = errno;
421 		return(cl);
422 	}
423 	if (*sockp < 0) {
424 		*sockp = _socket(AF_LOCAL, SOCK_STREAM, 0);
425 		len = raddr->sun_len = SUN_LEN(raddr);
426 		if ((*sockp < 0) || (_connect(*sockp,
427 		    (struct sockaddr *)raddr, len) < 0)) {
428 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
429 			rpc_createerr.cf_error.re_errno = errno;
430 			if (*sockp != -1)
431 				_close(*sockp);
432 			goto done;
433 		}
434 	}
435 	svcaddr->buf = raddr;
436 	svcaddr->len = raddr->sun_len;
437 	svcaddr->maxlen = sizeof (struct sockaddr_un);
438 	cl = clnt_vc_create(*sockp, svcaddr, prog,
439 	    vers, sendsz, recvsz);
440 done:
441 	free(svcaddr->buf);
442 	free(svcaddr);
443 	return(cl);
444 }
445 
446 /*
447  * Creates, registers, and returns a (rpc) unix based transporter.
448  * Obsoleted by svc_vc_create().
449  */
450 SVCXPRT *
451 svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path)
452 {
453 	struct netconfig *nconf;
454 	void *localhandle;
455 	struct sockaddr_un sun;
456 	struct sockaddr *sa;
457 	struct t_bind taddr;
458 	SVCXPRT *xprt;
459 	int addrlen;
460 
461 	xprt = (SVCXPRT *)NULL;
462 	localhandle = setnetconfig();
463 	while ((nconf = getnetconfig(localhandle)) != NULL) {
464 		if (nconf->nc_protofmly != NULL &&
465 		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
466 			break;
467 	}
468 	if (nconf == NULL)
469 		return(xprt);
470 
471 	if ((sock = __rpc_nconf2fd(nconf)) < 0)
472 		goto done;
473 
474 	memset(&sun, 0, sizeof sun);
475 	sun.sun_family = AF_LOCAL;
476 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
477 	    sizeof(sun.sun_path))
478 		goto done;
479 	sun.sun_len = SUN_LEN(&sun);
480 	addrlen = sizeof (struct sockaddr_un);
481 	sa = (struct sockaddr *)&sun;
482 
483 	if (_bind(sock, sa, addrlen) < 0)
484 		goto done;
485 
486 	taddr.addr.len = taddr.addr.maxlen = addrlen;
487 	taddr.addr.buf = malloc(addrlen);
488 	if (taddr.addr.buf == NULL)
489 		goto done;
490 	memcpy(taddr.addr.buf, sa, addrlen);
491 
492 	if (nconf->nc_semantics != NC_TPI_CLTS) {
493 		if (_listen(sock, SOMAXCONN) < 0) {
494 			free(taddr.addr.buf);
495 			goto done;
496 		}
497 	}
498 
499 	xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
500 
501 done:
502 	endnetconfig(localhandle);
503 	return(xprt);
504 }
505 
506 /*
507  * Like svunix_create(), except the routine takes any *open* UNIX file
508  * descriptor as its first input. Obsoleted by svc_fd_create();
509  */
510 SVCXPRT *
511 svcunixfd_create(int fd, u_int sendsize, u_int recvsize)
512 {
513 	return (svc_fd_create(fd, sendsize, recvsize));
514 }
515 
516 #endif /* PORTMAP */
517