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