]> git.ipfire.org Git - thirdparty/glibc.git/blame - sunrpc/clnt_unix.c
ARM: Pass dl_hwcap to IFUNC resolver.
[thirdparty/glibc.git] / sunrpc / clnt_unix.c
CommitLineData
e852e889 1/*
ab09b221 2 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
e852e889 3 *
a7ab6ec8
UD
4 * Copyright (c) 2010, Oracle America, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of the "Oracle America, Inc." nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
e852e889 32 *
e852e889
UD
33 * TCP based RPC supports 'batched calls'.
34 * A sequence of calls may be batched-up in a send buffer. The rpc call
35 * return immediately to the client even though the call was not necessarily
36 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
37 * the rpc timeout value is zero (see clnt.h, rpc).
38 *
39 * Clients should NOT casually batch calls that in fact return results; that is,
40 * the server side should be aware that a call is batched and not produce any
41 * return message. Batched calls that produce many result messages can
42 * deadlock (netlock) the client and the server....
43 *
44 * Now go hang yourself.
45 */
46
47#include <netdb.h>
48#include <errno.h>
49#include <stdio.h>
50#include <unistd.h>
4360eafd 51#include <libintl.h>
e852e889
UD
52#include <rpc/rpc.h>
53#include <sys/uio.h>
54#include <sys/poll.h>
55#include <sys/socket.h>
56#include <rpc/pmap_clnt.h>
3ce1f295 57#include <wchar.h>
e852e889 58
090ca000
UD
59extern u_long _create_xid (void);
60
e852e889
UD
61#define MCALL_MSG_SIZE 24
62
63struct ct_data
64 {
65 int ct_sock;
66 bool_t ct_closeit;
67 struct timeval ct_wait;
68 bool_t ct_waitset; /* wait set by clnt_control? */
69 struct sockaddr_un ct_addr;
70 struct rpc_err ct_error;
71 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
72 u_int ct_mpos; /* pos after marshal */
73 XDR ct_xdrs;
74 };
75
76static int readunix (char *, char *, int);
77static int writeunix (char *, char *, int);
78
79static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
80 xdrproc_t, caddr_t, struct timeval);
81static void clntunix_abort (void);
82static void clntunix_geterr (CLIENT *, struct rpc_err *);
83static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
84static bool_t clntunix_control (CLIENT *, int, char *);
85static void clntunix_destroy (CLIENT *);
86
31d7b14c 87static const struct clnt_ops unix_ops =
e852e889
UD
88{
89 clntunix_call,
90 clntunix_abort,
91 clntunix_geterr,
92 clntunix_freeres,
93 clntunix_destroy,
94 clntunix_control
95};
96
97/*
98 * Create a client handle for a tcp/ip connection.
99 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
100 * connected to raddr. If *sockp non-negative then
101 * raddr is ignored. The rpc/tcp package does buffering
102 * similar to stdio, so the client must pick send and receive buffer sizes,];
103 * 0 => use the default.
104 * If raddr->sin_port is 0, then a binder on the remote machine is
105 * consulted for the right port number.
106 * NB: *sockp is copied into a private area.
107 * NB: It is the clients responsibility to close *sockp.
108 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
109 * something more useful.
110 */
111CLIENT *
112clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
113 int *sockp, u_int sendsz, u_int recvsz)
114{
115 CLIENT *h;
116 struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
e852e889
UD
117 struct rpc_msg call_msg;
118 int len;
119
120 h = (CLIENT *) mem_alloc (sizeof (*h));
51028f34 121 if (h == NULL || ct == NULL)
e852e889 122 {
543cf8a9 123 struct rpc_createerr *ce = &get_rpc_createerr ();
1d20f7f8 124 (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
543cf8a9 125 ce->cf_stat = RPC_SYSTEMERROR;
51028f34 126 ce->cf_error.re_errno = ENOMEM;
e852e889
UD
127 goto fooy;
128 }
129
130 /*
131 * If no socket given, open one
132 */
133 if (*sockp < 0)
134 {
135 *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
136 len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
137 if (*sockp < 0
138 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
139 {
543cf8a9
UD
140 struct rpc_createerr *ce = &get_rpc_createerr ();
141 ce->cf_stat = RPC_SYSTEMERROR;
142 ce->cf_error.re_errno = errno;
e852e889
UD
143 if (*sockp != -1)
144 __close (*sockp);
145 goto fooy;
146 }
147 ct->ct_closeit = TRUE;
148 }
149 else
150 {
151 ct->ct_closeit = FALSE;
152 }
153
154 /*
155 * Set up private data struct
156 */
157 ct->ct_sock = *sockp;
158 ct->ct_wait.tv_usec = 0;
159 ct->ct_waitset = FALSE;
160 ct->ct_addr = *raddr;
161
162 /*
163 * Initialize call message
164 */
090ca000 165 call_msg.rm_xid = _create_xid ();
e852e889
UD
166 call_msg.rm_direction = CALL;
167 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
168 call_msg.rm_call.cb_prog = prog;
169 call_msg.rm_call.cb_vers = vers;
170
171 /*
172 * pre-serialize the static part of the call msg and stash it away
173 */
7b57bfe5
UD
174 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
175 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
e852e889
UD
176 {
177 if (ct->ct_closeit)
178 __close (*sockp);
179 goto fooy;
180 }
181 ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
182 XDR_DESTROY (&(ct->ct_xdrs));
183
184 /*
185 * Create a client handle which uses xdrrec for serialization
186 * and authnone for authentication.
187 */
7b57bfe5
UD
188 xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
189 (caddr_t) ct, readunix, writeunix);
31d7b14c 190 h->cl_ops = (struct clnt_ops *) &unix_ops;
e852e889 191 h->cl_private = (caddr_t) ct;
7b57bfe5 192 h->cl_auth = authnone_create ();
e852e889
UD
193 return h;
194
195fooy:
196 /*
197 * Something goofed, free stuff and barf
198 */
199 mem_free ((caddr_t) ct, sizeof (struct ct_data));
200 mem_free ((caddr_t) h, sizeof (CLIENT));
201 return (CLIENT *) NULL;
202}
021db4be 203libc_hidden_nolink_sunrpc (clntunix_create, GLIBC_2_1)
e852e889
UD
204
205static enum clnt_stat
206clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
207 CLIENT *h;
208 u_long proc;
209 xdrproc_t xdr_args;
210 caddr_t args_ptr;
211 xdrproc_t xdr_results;
212 caddr_t results_ptr;
213 struct timeval timeout;
214{
215 struct ct_data *ct = (struct ct_data *) h->cl_private;
216 XDR *xdrs = &(ct->ct_xdrs);
217 struct rpc_msg reply_msg;
218 u_long x_id;
219 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
220 bool_t shipnow;
221 int refreshes = 2;
222
223 if (!ct->ct_waitset)
224 {
225 ct->ct_wait = timeout;
226 }
227
228 shipnow =
a69a8d9c
UD
229 (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
230 && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
e852e889
UD
231
232call_again:
233 xdrs->x_op = XDR_ENCODE;
234 ct->ct_error.re_status = RPC_SUCCESS;
235 x_id = ntohl (--(*msg_x_id));
236 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
237 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
238 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
239 (!(*xdr_args) (xdrs, args_ptr)))
240 {
241 if (ct->ct_error.re_status == RPC_SUCCESS)
242 ct->ct_error.re_status = RPC_CANTENCODEARGS;
7b57bfe5 243 (void) xdrrec_endofrecord (xdrs, TRUE);
e852e889
UD
244 return ct->ct_error.re_status;
245 }
7b57bfe5 246 if (!xdrrec_endofrecord (xdrs, shipnow))
e852e889
UD
247 return ct->ct_error.re_status = RPC_CANTSEND;
248 if (!shipnow)
249 return RPC_SUCCESS;
250 /*
251 * Hack to provide rpc-based message passing
252 */
a69a8d9c 253 if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
e852e889
UD
254 return ct->ct_error.re_status = RPC_TIMEDOUT;
255
256
257 /*
258 * Keep receiving until we get a valid transaction id
259 */
260 xdrs->x_op = XDR_DECODE;
261 while (TRUE)
262 {
263 reply_msg.acpted_rply.ar_verf = _null_auth;
264 reply_msg.acpted_rply.ar_results.where = NULL;
7b57bfe5
UD
265 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
266 if (!xdrrec_skiprecord (xdrs))
e852e889
UD
267 return ct->ct_error.re_status;
268 /* now decode and validate the response header */
7b57bfe5 269 if (!xdr_replymsg (xdrs, &reply_msg))
e852e889
UD
270 {
271 if (ct->ct_error.re_status == RPC_SUCCESS)
272 continue;
273 return ct->ct_error.re_status;
274 }
275 if (reply_msg.rm_xid == x_id)
276 break;
277 }
278
279 /*
280 * process header
281 */
282 _seterr_reply (&reply_msg, &(ct->ct_error));
283 if (ct->ct_error.re_status == RPC_SUCCESS)
284 {
285 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
286 {
287 ct->ct_error.re_status = RPC_AUTHERROR;
288 ct->ct_error.re_why = AUTH_INVALIDRESP;
289 }
290 else if (!(*xdr_results) (xdrs, results_ptr))
291 {
292 if (ct->ct_error.re_status == RPC_SUCCESS)
293 ct->ct_error.re_status = RPC_CANTDECODERES;
294 }
295 /* free verifier ... */
296 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
297 {
298 xdrs->x_op = XDR_FREE;
7b57bfe5 299 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
e852e889
UD
300 }
301 } /* end successful completion */
302 else
303 {
304 /* maybe our credentials need to be refreshed ... */
305 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
306 goto call_again;
307 } /* end of unsuccessful completion */
308 return ct->ct_error.re_status;
309}
310
311static void
312clntunix_geterr (CLIENT *h, struct rpc_err *errp)
313{
314 struct ct_data *ct = (struct ct_data *) h->cl_private;
315
316 *errp = ct->ct_error;
317}
318
319static bool_t
320clntunix_freeres (cl, xdr_res, res_ptr)
321 CLIENT *cl;
322 xdrproc_t xdr_res;
323 caddr_t res_ptr;
324{
325 struct ct_data *ct = (struct ct_data *) cl->cl_private;
326 XDR *xdrs = &(ct->ct_xdrs);
327
328 xdrs->x_op = XDR_FREE;
329 return (*xdr_res) (xdrs, res_ptr);
330}
331
332static void
60d2f8f3 333clntunix_abort (void)
e852e889
UD
334{
335}
336
337static bool_t
338clntunix_control (CLIENT *cl, int request, char *info)
339{
340 struct ct_data *ct = (struct ct_data *) cl->cl_private;
4efbd5cb 341 u_long ul;
fb1ae1ee 342 u_int32_t ui32;
e852e889
UD
343
344 switch (request)
345 {
346 case CLSET_FD_CLOSE:
347 ct->ct_closeit = TRUE;
348 break;
349 case CLSET_FD_NCLOSE:
350 ct->ct_closeit = FALSE;
351 break;
352 case CLSET_TIMEOUT:
353 ct->ct_wait = *(struct timeval *) info;
354 break;
355 case CLGET_TIMEOUT:
356 *(struct timeval *) info = ct->ct_wait;
357 break;
358 case CLGET_SERVER_ADDR:
359 *(struct sockaddr_un *) info = ct->ct_addr;
360 break;
361 case CLGET_FD:
362 *(int *)info = ct->ct_sock;
363 break;
364 case CLGET_XID:
365 /*
366 * use the knowledge that xid is the
367 * first element in the call structure *.
368 * This will get the xid of the PREVIOUS call
369 */
fb1ae1ee
JM
370 memcpy (&ui32, ct->ct_mcall, sizeof (ui32));
371 ul = ntohl (ui32);
4efbd5cb 372 memcpy (info, &ul, sizeof (ul));
e852e889
UD
373 break;
374 case CLSET_XID:
375 /* This will set the xid of the NEXT call */
fb1ae1ee
JM
376 memcpy (&ul, info, sizeof (ul));
377 ui32 = htonl (ul - 1);
378 memcpy (ct->ct_mcall, &ui32, sizeof (ui32));
e852e889 379 /* decrement by 1 as clntunix_call() increments once */
f0ccf6ea 380 break;
e852e889
UD
381 case CLGET_VERS:
382 /*
383 * This RELIES on the information that, in the call body,
384 * the version number field is the fifth field from the
385 * begining of the RPC header. MUST be changed if the
386 * call_struct is changed
387 */
fb1ae1ee
JM
388 memcpy (&ui32, ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, sizeof (ui32));
389 ul = ntohl (ui32);
390 memcpy (info, &ul, sizeof (ul));
e852e889
UD
391 break;
392 case CLSET_VERS:
fb1ae1ee
JM
393 memcpy (&ul, info, sizeof (ul));
394 ui32 = htonl (ul);
395 memcpy (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
e852e889
UD
396 break;
397 case CLGET_PROG:
398 /*
399 * This RELIES on the information that, in the call body,
400 * the program number field is the field from the
401 * begining of the RPC header. MUST be changed if the
402 * call_struct is changed
403 */
fb1ae1ee
JM
404 memcpy (&ui32, ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, sizeof (ui32));
405 ul = ntohl (ui32);
406 memcpy (info, &ul, sizeof (ul));
e852e889
UD
407 break;
408 case CLSET_PROG:
fb1ae1ee
JM
409 memcpy (&ul, info, sizeof (ul));
410 ui32 = htonl (ul);
411 memcpy (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
e852e889
UD
412 break;
413 /* The following are only possible with TI-RPC */
414 case CLGET_RETRY_TIMEOUT:
415 case CLSET_RETRY_TIMEOUT:
416 case CLGET_SVC_ADDR:
417 case CLSET_SVC_ADDR:
418 case CLSET_PUSH_TIMOD:
419 case CLSET_POP_TIMOD:
420 default:
421 return FALSE;
422 }
423 return TRUE;
424}
425
426
427static void
428clntunix_destroy (CLIENT *h)
429{
430 struct ct_data *ct =
431 (struct ct_data *) h->cl_private;
432
433 if (ct->ct_closeit)
434 {
c0b50509 435 (void) __close (ct->ct_sock);
e852e889
UD
436 }
437 XDR_DESTROY (&(ct->ct_xdrs));
438 mem_free ((caddr_t) ct, sizeof (struct ct_data));
439 mem_free ((caddr_t) h, sizeof (CLIENT));
440}
441
e852e889 442static int
d1275afe 443__msgread (int sock, void *data, size_t cnt)
e852e889 444{
d1275afe 445 struct iovec iov;
e852e889 446 struct msghdr msg;
c5720a93 447#ifdef SCM_CREDENTIALS
d1275afe 448 static char cm[CMSG_SPACE(sizeof (struct ucred))];
c5720a93 449#endif
d1275afe 450 int len;
e852e889 451
d1275afe
AS
452 iov.iov_base = data;
453 iov.iov_len = cnt;
e852e889 454
d1275afe 455 msg.msg_iov = &iov;
e852e889
UD
456 msg.msg_iovlen = 1;
457 msg.msg_name = NULL;
458 msg.msg_namelen = 0;
c5720a93 459#ifdef SCM_CREDENTIALS
d1275afe
AS
460 msg.msg_control = (caddr_t) &cm;
461 msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
c5720a93 462#endif
e852e889
UD
463 msg.msg_flags = 0;
464
7cabd57c 465#ifdef SO_PASSCRED
d76240d7
RM
466 {
467 int on = 1;
b2bffca2 468 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
d76240d7
RM
469 return -1;
470 }
7cabd57c 471#endif
e852e889 472
d1275afe 473 restart:
b2bffca2 474 len = __recvmsg (sock, &msg, 0);
d1275afe
AS
475 if (len >= 0)
476 {
477 if (msg.msg_flags & MSG_CTRUNC || len == 0)
478 return 0;
479 else
480 return len;
481 }
482 if (errno == EINTR)
483 goto restart;
484 return -1;
e852e889
UD
485}
486
487static int
d1275afe 488__msgwrite (int sock, void *data, size_t cnt)
e852e889 489{
7ce241a0 490#ifndef SCM_CREDENTIALS
e852e889
UD
491 /* We cannot implement this reliably. */
492 __set_errno (ENOSYS);
786a5421 493 return -1;
e852e889 494#else
d1275afe 495 struct iovec iov;
e852e889 496 struct msghdr msg;
d1275afe
AS
497 struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
498 struct ucred cred;
499 int len;
e852e889 500
e852e889
UD
501 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
502 get?id(). But since keyserv needs geteuid(), we have no other chance.
503 It would be much better, if the kernel could pass both to the server. */
d1275afe
AS
504 cred.pid = __getpid ();
505 cred.uid = __geteuid ();
506 cred.gid = __getegid ();
507
508 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
509 cmsg->cmsg_level = SOL_SOCKET;
510 cmsg->cmsg_type = SCM_CREDENTIALS;
511 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
e852e889 512
d1275afe
AS
513 iov.iov_base = data;
514 iov.iov_len = cnt;
515
516 msg.msg_iov = &iov;
e852e889
UD
517 msg.msg_iovlen = 1;
518 msg.msg_name = NULL;
519 msg.msg_namelen = 0;
d1275afe
AS
520 msg.msg_control = cmsg;
521 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
e852e889
UD
522 msg.msg_flags = 0;
523
d1275afe 524 restart:
b2bffca2 525 len = __sendmsg (sock, &msg, 0);
d1275afe
AS
526 if (len >= 0)
527 return len;
528 if (errno == EINTR)
529 goto restart;
530 return -1;
531
e852e889
UD
532#endif
533}
534
535
536/*
537 * Interface between xdr serializer and unix connection.
538 * Behaves like the system calls, read & write, but keeps some error state
539 * around for the rpc level.
540 */
541static int
542readunix (char *ctptr, char *buf, int len)
543{
544 struct ct_data *ct = (struct ct_data *) ctptr;
545 struct pollfd fd;
546 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
547 + (ct->ct_wait.tv_usec / 1000));
548
549 if (len == 0)
550 return 0;
551
552 fd.fd = ct->ct_sock;
553 fd.events = POLLIN;
554 while (TRUE)
555 {
556 switch (__poll (&fd, 1, milliseconds))
7b57bfe5
UD
557 {
558 case 0:
559 ct->ct_error.re_status = RPC_TIMEDOUT;
560 return -1;
561
562 case -1:
563 if (errno == EINTR)
564 continue;
565 ct->ct_error.re_status = RPC_CANTRECV;
566 ct->ct_error.re_errno = errno;
567 return -1;
568 }
e852e889
UD
569 break;
570 }
571 switch (len = __msgread (ct->ct_sock, buf, len))
572 {
573
574 case 0:
575 /* premature eof */
576 ct->ct_error.re_errno = ECONNRESET;
577 ct->ct_error.re_status = RPC_CANTRECV;
578 len = -1; /* it's really an error */
579 break;
580
581 case -1:
582 ct->ct_error.re_errno = errno;
583 ct->ct_error.re_status = RPC_CANTRECV;
584 break;
585 }
586 return len;
587}
588
589static int
590writeunix (char *ctptr, char *buf, int len)
591{
592 int i, cnt;
593 struct ct_data *ct = (struct ct_data *) ctptr;
594
595 for (cnt = len; cnt > 0; cnt -= i, buf += i)
596 {
597 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
598 {
599 ct->ct_error.re_errno = errno;
600 ct->ct_error.re_status = RPC_CANTSEND;
601 return -1;
602 }
603 }
604 return len;
605}