]> git.ipfire.org Git - thirdparty/glibc.git/blame - sunrpc/clnt_unix.c
sunrpc: Always obtain AF_INET addresses from NSS [BZ #20964]
[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
f63f2bfd
JM
206clntunix_call (CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
207 xdrproc_t xdr_results, caddr_t results_ptr,
208 struct timeval timeout)
e852e889
UD
209{
210 struct ct_data *ct = (struct ct_data *) h->cl_private;
211 XDR *xdrs = &(ct->ct_xdrs);
212 struct rpc_msg reply_msg;
213 u_long x_id;
214 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
215 bool_t shipnow;
216 int refreshes = 2;
217
218 if (!ct->ct_waitset)
219 {
220 ct->ct_wait = timeout;
221 }
222
223 shipnow =
a69a8d9c
UD
224 (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
225 && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
e852e889
UD
226
227call_again:
228 xdrs->x_op = XDR_ENCODE;
229 ct->ct_error.re_status = RPC_SUCCESS;
230 x_id = ntohl (--(*msg_x_id));
231 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
232 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
233 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
234 (!(*xdr_args) (xdrs, args_ptr)))
235 {
236 if (ct->ct_error.re_status == RPC_SUCCESS)
237 ct->ct_error.re_status = RPC_CANTENCODEARGS;
7b57bfe5 238 (void) xdrrec_endofrecord (xdrs, TRUE);
e852e889
UD
239 return ct->ct_error.re_status;
240 }
7b57bfe5 241 if (!xdrrec_endofrecord (xdrs, shipnow))
e852e889
UD
242 return ct->ct_error.re_status = RPC_CANTSEND;
243 if (!shipnow)
244 return RPC_SUCCESS;
245 /*
246 * Hack to provide rpc-based message passing
247 */
a69a8d9c 248 if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
e852e889
UD
249 return ct->ct_error.re_status = RPC_TIMEDOUT;
250
251
252 /*
253 * Keep receiving until we get a valid transaction id
254 */
255 xdrs->x_op = XDR_DECODE;
256 while (TRUE)
257 {
258 reply_msg.acpted_rply.ar_verf = _null_auth;
259 reply_msg.acpted_rply.ar_results.where = NULL;
7b57bfe5
UD
260 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
261 if (!xdrrec_skiprecord (xdrs))
e852e889
UD
262 return ct->ct_error.re_status;
263 /* now decode and validate the response header */
7b57bfe5 264 if (!xdr_replymsg (xdrs, &reply_msg))
e852e889
UD
265 {
266 if (ct->ct_error.re_status == RPC_SUCCESS)
267 continue;
268 return ct->ct_error.re_status;
269 }
270 if (reply_msg.rm_xid == x_id)
271 break;
272 }
273
274 /*
275 * process header
276 */
277 _seterr_reply (&reply_msg, &(ct->ct_error));
278 if (ct->ct_error.re_status == RPC_SUCCESS)
279 {
280 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
281 {
282 ct->ct_error.re_status = RPC_AUTHERROR;
283 ct->ct_error.re_why = AUTH_INVALIDRESP;
284 }
285 else if (!(*xdr_results) (xdrs, results_ptr))
286 {
287 if (ct->ct_error.re_status == RPC_SUCCESS)
288 ct->ct_error.re_status = RPC_CANTDECODERES;
289 }
290 /* free verifier ... */
291 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
292 {
293 xdrs->x_op = XDR_FREE;
7b57bfe5 294 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
e852e889
UD
295 }
296 } /* end successful completion */
297 else
298 {
299 /* maybe our credentials need to be refreshed ... */
300 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
301 goto call_again;
302 } /* end of unsuccessful completion */
303 return ct->ct_error.re_status;
304}
305
306static void
307clntunix_geterr (CLIENT *h, struct rpc_err *errp)
308{
309 struct ct_data *ct = (struct ct_data *) h->cl_private;
310
311 *errp = ct->ct_error;
312}
313
314static bool_t
9d46370c 315clntunix_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
e852e889
UD
316{
317 struct ct_data *ct = (struct ct_data *) cl->cl_private;
318 XDR *xdrs = &(ct->ct_xdrs);
319
320 xdrs->x_op = XDR_FREE;
321 return (*xdr_res) (xdrs, res_ptr);
322}
323
324static void
60d2f8f3 325clntunix_abort (void)
e852e889
UD
326{
327}
328
329static bool_t
330clntunix_control (CLIENT *cl, int request, char *info)
331{
332 struct ct_data *ct = (struct ct_data *) cl->cl_private;
4efbd5cb 333 u_long ul;
fb1ae1ee 334 u_int32_t ui32;
e852e889
UD
335
336 switch (request)
337 {
338 case CLSET_FD_CLOSE:
339 ct->ct_closeit = TRUE;
340 break;
341 case CLSET_FD_NCLOSE:
342 ct->ct_closeit = FALSE;
343 break;
344 case CLSET_TIMEOUT:
345 ct->ct_wait = *(struct timeval *) info;
346 break;
347 case CLGET_TIMEOUT:
348 *(struct timeval *) info = ct->ct_wait;
349 break;
350 case CLGET_SERVER_ADDR:
351 *(struct sockaddr_un *) info = ct->ct_addr;
352 break;
353 case CLGET_FD:
354 *(int *)info = ct->ct_sock;
355 break;
356 case CLGET_XID:
357 /*
358 * use the knowledge that xid is the
359 * first element in the call structure *.
360 * This will get the xid of the PREVIOUS call
361 */
fb1ae1ee
JM
362 memcpy (&ui32, ct->ct_mcall, sizeof (ui32));
363 ul = ntohl (ui32);
4efbd5cb 364 memcpy (info, &ul, sizeof (ul));
e852e889
UD
365 break;
366 case CLSET_XID:
367 /* This will set the xid of the NEXT call */
fb1ae1ee
JM
368 memcpy (&ul, info, sizeof (ul));
369 ui32 = htonl (ul - 1);
370 memcpy (ct->ct_mcall, &ui32, sizeof (ui32));
e852e889 371 /* decrement by 1 as clntunix_call() increments once */
f0ccf6ea 372 break;
e852e889
UD
373 case CLGET_VERS:
374 /*
375 * This RELIES on the information that, in the call body,
376 * the version number field is the fifth field from the
6f65e668 377 * beginning of the RPC header. MUST be changed if the
e852e889
UD
378 * call_struct is changed
379 */
fb1ae1ee
JM
380 memcpy (&ui32, ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, sizeof (ui32));
381 ul = ntohl (ui32);
382 memcpy (info, &ul, sizeof (ul));
e852e889
UD
383 break;
384 case CLSET_VERS:
fb1ae1ee
JM
385 memcpy (&ul, info, sizeof (ul));
386 ui32 = htonl (ul);
387 memcpy (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
e852e889
UD
388 break;
389 case CLGET_PROG:
390 /*
391 * This RELIES on the information that, in the call body,
392 * the program number field is the field from the
6f65e668 393 * beginning of the RPC header. MUST be changed if the
e852e889
UD
394 * call_struct is changed
395 */
fb1ae1ee
JM
396 memcpy (&ui32, ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, sizeof (ui32));
397 ul = ntohl (ui32);
398 memcpy (info, &ul, sizeof (ul));
e852e889
UD
399 break;
400 case CLSET_PROG:
fb1ae1ee
JM
401 memcpy (&ul, info, sizeof (ul));
402 ui32 = htonl (ul);
403 memcpy (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
e852e889
UD
404 break;
405 /* The following are only possible with TI-RPC */
406 case CLGET_RETRY_TIMEOUT:
407 case CLSET_RETRY_TIMEOUT:
408 case CLGET_SVC_ADDR:
409 case CLSET_SVC_ADDR:
410 case CLSET_PUSH_TIMOD:
411 case CLSET_POP_TIMOD:
412 default:
413 return FALSE;
414 }
415 return TRUE;
416}
417
418
419static void
420clntunix_destroy (CLIENT *h)
421{
422 struct ct_data *ct =
423 (struct ct_data *) h->cl_private;
424
425 if (ct->ct_closeit)
426 {
c0b50509 427 (void) __close (ct->ct_sock);
e852e889
UD
428 }
429 XDR_DESTROY (&(ct->ct_xdrs));
430 mem_free ((caddr_t) ct, sizeof (struct ct_data));
431 mem_free ((caddr_t) h, sizeof (CLIENT));
432}
433
e852e889 434static int
d1275afe 435__msgread (int sock, void *data, size_t cnt)
e852e889 436{
d1275afe 437 struct iovec iov;
e852e889 438 struct msghdr msg;
c5720a93 439#ifdef SCM_CREDENTIALS
d1275afe 440 static char cm[CMSG_SPACE(sizeof (struct ucred))];
c5720a93 441#endif
d1275afe 442 int len;
e852e889 443
d1275afe
AS
444 iov.iov_base = data;
445 iov.iov_len = cnt;
e852e889 446
d1275afe 447 msg.msg_iov = &iov;
e852e889
UD
448 msg.msg_iovlen = 1;
449 msg.msg_name = NULL;
450 msg.msg_namelen = 0;
c5720a93 451#ifdef SCM_CREDENTIALS
d1275afe
AS
452 msg.msg_control = (caddr_t) &cm;
453 msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
c5720a93 454#endif
e852e889
UD
455 msg.msg_flags = 0;
456
7cabd57c 457#ifdef SO_PASSCRED
d76240d7
RM
458 {
459 int on = 1;
b2bffca2 460 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
d76240d7
RM
461 return -1;
462 }
7cabd57c 463#endif
e852e889 464
d1275afe 465 restart:
b2bffca2 466 len = __recvmsg (sock, &msg, 0);
d1275afe
AS
467 if (len >= 0)
468 {
469 if (msg.msg_flags & MSG_CTRUNC || len == 0)
470 return 0;
471 else
472 return len;
473 }
474 if (errno == EINTR)
475 goto restart;
476 return -1;
e852e889
UD
477}
478
479static int
d1275afe 480__msgwrite (int sock, void *data, size_t cnt)
e852e889 481{
7ce241a0 482#ifndef SCM_CREDENTIALS
e852e889
UD
483 /* We cannot implement this reliably. */
484 __set_errno (ENOSYS);
786a5421 485 return -1;
e852e889 486#else
d1275afe 487 struct iovec iov;
e852e889 488 struct msghdr msg;
d1275afe
AS
489 struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
490 struct ucred cred;
491 int len;
e852e889 492
e852e889
UD
493 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
494 get?id(). But since keyserv needs geteuid(), we have no other chance.
495 It would be much better, if the kernel could pass both to the server. */
d1275afe
AS
496 cred.pid = __getpid ();
497 cred.uid = __geteuid ();
498 cred.gid = __getegid ();
499
500 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
501 cmsg->cmsg_level = SOL_SOCKET;
502 cmsg->cmsg_type = SCM_CREDENTIALS;
503 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
e852e889 504
d1275afe
AS
505 iov.iov_base = data;
506 iov.iov_len = cnt;
507
508 msg.msg_iov = &iov;
e852e889
UD
509 msg.msg_iovlen = 1;
510 msg.msg_name = NULL;
511 msg.msg_namelen = 0;
d1275afe
AS
512 msg.msg_control = cmsg;
513 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
e852e889
UD
514 msg.msg_flags = 0;
515
d1275afe 516 restart:
b2bffca2 517 len = __sendmsg (sock, &msg, 0);
d1275afe
AS
518 if (len >= 0)
519 return len;
520 if (errno == EINTR)
521 goto restart;
522 return -1;
523
e852e889
UD
524#endif
525}
526
527
528/*
529 * Interface between xdr serializer and unix connection.
530 * Behaves like the system calls, read & write, but keeps some error state
531 * around for the rpc level.
532 */
533static int
534readunix (char *ctptr, char *buf, int len)
535{
536 struct ct_data *ct = (struct ct_data *) ctptr;
537 struct pollfd fd;
538 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
539 + (ct->ct_wait.tv_usec / 1000));
540
541 if (len == 0)
542 return 0;
543
544 fd.fd = ct->ct_sock;
545 fd.events = POLLIN;
546 while (TRUE)
547 {
548 switch (__poll (&fd, 1, milliseconds))
7b57bfe5
UD
549 {
550 case 0:
551 ct->ct_error.re_status = RPC_TIMEDOUT;
552 return -1;
553
554 case -1:
555 if (errno == EINTR)
556 continue;
557 ct->ct_error.re_status = RPC_CANTRECV;
558 ct->ct_error.re_errno = errno;
559 return -1;
560 }
e852e889
UD
561 break;
562 }
563 switch (len = __msgread (ct->ct_sock, buf, len))
564 {
565
566 case 0:
567 /* premature eof */
568 ct->ct_error.re_errno = ECONNRESET;
569 ct->ct_error.re_status = RPC_CANTRECV;
570 len = -1; /* it's really an error */
571 break;
572
573 case -1:
574 ct->ct_error.re_errno = errno;
575 ct->ct_error.re_status = RPC_CANTRECV;
576 break;
577 }
578 return len;
579}
580
581static int
582writeunix (char *ctptr, char *buf, int len)
583{
584 int i, cnt;
585 struct ct_data *ct = (struct ct_data *) ctptr;
586
587 for (cnt = len; cnt > 0; cnt -= i, buf += i)
588 {
589 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
590 {
591 ct->ct_error.re_errno = errno;
592 ct->ct_error.re_status = RPC_CANTSEND;
593 return -1;
594 }
595 }
596 return len;
597}