]> git.ipfire.org Git - thirdparty/glibc.git/blob - sunrpc/clnt_unix.c
Fix aliasing issues in RPC code
[thirdparty/glibc.git] / sunrpc / clnt_unix.c
1 /*
2 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
3 *
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.
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>
51 #include <libintl.h>
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>
57 #include <wchar.h>
58
59 extern u_long _create_xid (void);
60
61 #define MCALL_MSG_SIZE 24
62
63 struct 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
76 static int readunix (char *, char *, int);
77 static int writeunix (char *, char *, int);
78
79 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
80 xdrproc_t, caddr_t, struct timeval);
81 static void clntunix_abort (void);
82 static void clntunix_geterr (CLIENT *, struct rpc_err *);
83 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
84 static bool_t clntunix_control (CLIENT *, int, char *);
85 static void clntunix_destroy (CLIENT *);
86
87 static const struct clnt_ops unix_ops =
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 */
111 CLIENT *
112 clntunix_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));
117 struct rpc_msg call_msg;
118 int len;
119
120 h = (CLIENT *) mem_alloc (sizeof (*h));
121 if (h == NULL || ct == NULL)
122 {
123 struct rpc_createerr *ce = &get_rpc_createerr ();
124 (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
125 ce->cf_stat = RPC_SYSTEMERROR;
126 ce->cf_error.re_errno = ENOMEM;
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 {
140 struct rpc_createerr *ce = &get_rpc_createerr ();
141 ce->cf_stat = RPC_SYSTEMERROR;
142 ce->cf_error.re_errno = errno;
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 */
165 call_msg.rm_xid = _create_xid ();
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 */
174 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
175 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
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 */
188 xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
189 (caddr_t) ct, readunix, writeunix);
190 h->cl_ops = (struct clnt_ops *) &unix_ops;
191 h->cl_private = (caddr_t) ct;
192 h->cl_auth = authnone_create ();
193 return h;
194
195 fooy:
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 }
203 libc_hidden_nolink (clntunix_create, GLIBC_2_1)
204
205 static enum clnt_stat
206 clntunix_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 =
229 (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
230 && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
231
232 call_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;
243 (void) xdrrec_endofrecord (xdrs, TRUE);
244 return ct->ct_error.re_status;
245 }
246 if (!xdrrec_endofrecord (xdrs, shipnow))
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 */
253 if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
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;
265 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
266 if (!xdrrec_skiprecord (xdrs))
267 return ct->ct_error.re_status;
268 /* now decode and validate the response header */
269 if (!xdr_replymsg (xdrs, &reply_msg))
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;
299 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
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
311 static void
312 clntunix_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
319 static bool_t
320 clntunix_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
332 static void
333 clntunix_abort ()
334 {
335 }
336
337 static bool_t
338 clntunix_control (CLIENT *cl, int request, char *info)
339 {
340 struct ct_data *ct = (struct ct_data *) cl->cl_private;
341 u_long *mcall_ptr;
342 u_long ul;
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 */
370 #if 0
371 /* This original code has aliasing issues. */
372 *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
373 #else
374 mcall_ptr = (u_long *)ct->ct_mcall;
375 ul = ntohl (*mcall_ptr);
376 memcpy (info, &ul, sizeof (ul));
377 #endif
378 break;
379 case CLSET_XID:
380 /* This will set the xid of the NEXT call */
381 #if 0
382 /* This original code has aliasing issues. */
383 *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
384 #else
385 ul = ntohl (*(u_long *)info - 1);
386 memcpy (ct->ct_mcall, &ul, sizeof (ul));
387 #endif
388 /* decrement by 1 as clntunix_call() increments once */
389 break;
390 case CLGET_VERS:
391 /*
392 * This RELIES on the information that, in the call body,
393 * the version number field is the fifth field from the
394 * begining of the RPC header. MUST be changed if the
395 * call_struct is changed
396 */
397 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
398 + 4 * BYTES_PER_XDR_UNIT));
399 break;
400 case CLSET_VERS:
401 *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
402 = htonl (*(u_long *) info);
403 break;
404 case CLGET_PROG:
405 /*
406 * This RELIES on the information that, in the call body,
407 * the program number field is the field from the
408 * begining of the RPC header. MUST be changed if the
409 * call_struct is changed
410 */
411 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
412 + 3 * BYTES_PER_XDR_UNIT));
413 break;
414 case CLSET_PROG:
415 *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
416 = htonl(*(u_long *) info);
417 break;
418 /* The following are only possible with TI-RPC */
419 case CLGET_RETRY_TIMEOUT:
420 case CLSET_RETRY_TIMEOUT:
421 case CLGET_SVC_ADDR:
422 case CLSET_SVC_ADDR:
423 case CLSET_PUSH_TIMOD:
424 case CLSET_POP_TIMOD:
425 default:
426 return FALSE;
427 }
428 return TRUE;
429 }
430
431
432 static void
433 clntunix_destroy (CLIENT *h)
434 {
435 struct ct_data *ct =
436 (struct ct_data *) h->cl_private;
437
438 if (ct->ct_closeit)
439 {
440 (void) __close (ct->ct_sock);
441 }
442 XDR_DESTROY (&(ct->ct_xdrs));
443 mem_free ((caddr_t) ct, sizeof (struct ct_data));
444 mem_free ((caddr_t) h, sizeof (CLIENT));
445 }
446
447 static int
448 __msgread (int sock, void *data, size_t cnt)
449 {
450 struct iovec iov;
451 struct msghdr msg;
452 #ifdef SCM_CREDENTIALS
453 static char cm[CMSG_SPACE(sizeof (struct ucred))];
454 #endif
455 int len;
456
457 iov.iov_base = data;
458 iov.iov_len = cnt;
459
460 msg.msg_iov = &iov;
461 msg.msg_iovlen = 1;
462 msg.msg_name = NULL;
463 msg.msg_namelen = 0;
464 #ifdef SCM_CREDENTIALS
465 msg.msg_control = (caddr_t) &cm;
466 msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
467 #endif
468 msg.msg_flags = 0;
469
470 #ifdef SO_PASSCRED
471 {
472 int on = 1;
473 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
474 return -1;
475 }
476 #endif
477
478 restart:
479 len = __recvmsg (sock, &msg, 0);
480 if (len >= 0)
481 {
482 if (msg.msg_flags & MSG_CTRUNC || len == 0)
483 return 0;
484 else
485 return len;
486 }
487 if (errno == EINTR)
488 goto restart;
489 return -1;
490 }
491
492 static int
493 __msgwrite (int sock, void *data, size_t cnt)
494 {
495 #ifndef SCM_CREDENTIALS
496 /* We cannot implement this reliably. */
497 __set_errno (ENOSYS);
498 return -1;
499 #else
500 struct iovec iov;
501 struct msghdr msg;
502 struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
503 struct ucred cred;
504 int len;
505
506 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
507 get?id(). But since keyserv needs geteuid(), we have no other chance.
508 It would be much better, if the kernel could pass both to the server. */
509 cred.pid = __getpid ();
510 cred.uid = __geteuid ();
511 cred.gid = __getegid ();
512
513 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
514 cmsg->cmsg_level = SOL_SOCKET;
515 cmsg->cmsg_type = SCM_CREDENTIALS;
516 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
517
518 iov.iov_base = data;
519 iov.iov_len = cnt;
520
521 msg.msg_iov = &iov;
522 msg.msg_iovlen = 1;
523 msg.msg_name = NULL;
524 msg.msg_namelen = 0;
525 msg.msg_control = cmsg;
526 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
527 msg.msg_flags = 0;
528
529 restart:
530 len = __sendmsg (sock, &msg, 0);
531 if (len >= 0)
532 return len;
533 if (errno == EINTR)
534 goto restart;
535 return -1;
536
537 #endif
538 }
539
540
541 /*
542 * Interface between xdr serializer and unix connection.
543 * Behaves like the system calls, read & write, but keeps some error state
544 * around for the rpc level.
545 */
546 static int
547 readunix (char *ctptr, char *buf, int len)
548 {
549 struct ct_data *ct = (struct ct_data *) ctptr;
550 struct pollfd fd;
551 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
552 + (ct->ct_wait.tv_usec / 1000));
553
554 if (len == 0)
555 return 0;
556
557 fd.fd = ct->ct_sock;
558 fd.events = POLLIN;
559 while (TRUE)
560 {
561 switch (__poll (&fd, 1, milliseconds))
562 {
563 case 0:
564 ct->ct_error.re_status = RPC_TIMEDOUT;
565 return -1;
566
567 case -1:
568 if (errno == EINTR)
569 continue;
570 ct->ct_error.re_status = RPC_CANTRECV;
571 ct->ct_error.re_errno = errno;
572 return -1;
573 }
574 break;
575 }
576 switch (len = __msgread (ct->ct_sock, buf, len))
577 {
578
579 case 0:
580 /* premature eof */
581 ct->ct_error.re_errno = ECONNRESET;
582 ct->ct_error.re_status = RPC_CANTRECV;
583 len = -1; /* it's really an error */
584 break;
585
586 case -1:
587 ct->ct_error.re_errno = errno;
588 ct->ct_error.re_status = RPC_CANTRECV;
589 break;
590 }
591 return len;
592 }
593
594 static int
595 writeunix (char *ctptr, char *buf, int len)
596 {
597 int i, cnt;
598 struct ct_data *ct = (struct ct_data *) ctptr;
599
600 for (cnt = len; cnt > 0; cnt -= i, buf += i)
601 {
602 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
603 {
604 ct->ct_error.re_errno = errno;
605 ct->ct_error.re_status = RPC_CANTSEND;
606 return -1;
607 }
608 }
609 return len;
610 }