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