rpc_svc_calls(3): Remove __svc_getcallercreds() documentation.
[dragonfly.git] / lib / libc / rpc / rpc_soc.c
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 */