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