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.
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.
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.
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.
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.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
31 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
33 * Copyright (C) 1984, Sun Microsystems, Inc.
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).
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....
46 * Now go hang yourself.
59 #include <sys/socket.h>
60 #include <rpc/pmap_clnt.h>
66 extern u_long _create_xid (void) attribute_hidden;
68 #define MCALL_MSG_SIZE 24
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 */
83 static int readunix (char *, char *, int);
84 static int writeunix (char *, char *, int);
86 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
87 xdrproc_t, caddr_t, struct timeval);
88 static void clntunix_abort (void);
89 static void clntunix_geterr (CLIENT *, struct rpc_err *);
90 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
91 static bool_t clntunix_control (CLIENT *, int, char *);
92 static void clntunix_destroy (CLIENT *);
94 static const struct clnt_ops unix_ops =
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.
119 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
120 int *sockp, u_int sendsz, u_int recvsz)
123 struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
124 struct rpc_msg call_msg;
127 h = (CLIENT *) mem_alloc (sizeof (*h));
128 if (h == NULL || ct == NULL)
130 struct rpc_createerr *ce = &get_rpc_createerr ();
132 if (_IO_fwide (stderr, 0) > 0)
133 (void) fwprintf (stderr, L"%s",
134 _("clntunix_create: out of memory\n"));
137 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
138 ce->cf_stat = RPC_SYSTEMERROR;
139 ce->cf_error.re_errno = ENOMEM;
144 * If no socket given, open one
148 *sockp = socket (AF_UNIX, SOCK_STREAM, 0);
149 len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
151 || connect (*sockp, (struct sockaddr *) raddr, len) < 0)
153 struct rpc_createerr *ce = &get_rpc_createerr ();
154 ce->cf_stat = RPC_SYSTEMERROR;
155 ce->cf_error.re_errno = errno;
160 ct->ct_closeit = TRUE;
164 ct->ct_closeit = FALSE;
168 * Set up private data struct
170 ct->ct_sock = *sockp;
171 ct->ct_wait.tv_usec = 0;
172 ct->ct_waitset = FALSE;
173 ct->ct_addr = *raddr;
176 * Initialize call message
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;
185 * pre-serialize the static part of the call msg and stash it away
187 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
188 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
194 ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
195 XDR_DESTROY (&(ct->ct_xdrs));
198 * Create a client handle which uses xdrrec for serialization
199 * and authnone for authentication.
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 ();
210 * Something goofed, free stuff and barf
212 mem_free ((caddr_t) ct, sizeof (struct ct_data));
213 mem_free ((caddr_t) h, sizeof (CLIENT));
214 return (CLIENT *) NULL;
216 libc_hidden_def(clntunix_create)
218 static enum clnt_stat
219 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
224 xdrproc_t xdr_results;
226 struct timeval timeout;
228 struct ct_data *ct = (struct ct_data *) h->cl_private;
229 XDR *xdrs = &(ct->ct_xdrs);
230 struct rpc_msg reply_msg;
232 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
238 ct->ct_wait = timeout;
242 (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
243 && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
246 xdrs->x_op = XDR_ENCODE;
247 ct->ct_error.re_status = RPC_SUCCESS;
248 x_id = ntohl (--(*msg_x_id));
249 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
250 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
251 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
252 (!(*xdr_args) (xdrs, args_ptr)))
254 if (ct->ct_error.re_status == RPC_SUCCESS)
255 ct->ct_error.re_status = RPC_CANTENCODEARGS;
256 (void) xdrrec_endofrecord (xdrs, TRUE);
257 return ct->ct_error.re_status;
259 if (!xdrrec_endofrecord (xdrs, shipnow))
260 return ct->ct_error.re_status = RPC_CANTSEND;
264 * Hack to provide rpc-based message passing
266 if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
267 return ct->ct_error.re_status = RPC_TIMEDOUT;
271 * Keep receiving until we get a valid transaction id
273 xdrs->x_op = XDR_DECODE;
276 reply_msg.acpted_rply.ar_verf = _null_auth;
277 reply_msg.acpted_rply.ar_results.where = NULL;
278 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
279 if (!xdrrec_skiprecord (xdrs))
280 return ct->ct_error.re_status;
281 /* now decode and validate the response header */
282 if (!xdr_replymsg (xdrs, &reply_msg))
284 if (ct->ct_error.re_status == RPC_SUCCESS)
286 return ct->ct_error.re_status;
288 if (reply_msg.rm_xid == x_id)
295 _seterr_reply (&reply_msg, &(ct->ct_error));
296 if (ct->ct_error.re_status == RPC_SUCCESS)
298 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
300 ct->ct_error.re_status = RPC_AUTHERROR;
301 ct->ct_error.re_why = AUTH_INVALIDRESP;
303 else if (!(*xdr_results) (xdrs, results_ptr))
305 if (ct->ct_error.re_status == RPC_SUCCESS)
306 ct->ct_error.re_status = RPC_CANTDECODERES;
308 /* free verifier ... */
309 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
311 xdrs->x_op = XDR_FREE;
312 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
314 } /* end successful completion */
317 /* maybe our credentials need to be refreshed ... */
318 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
320 } /* end of unsuccessful completion */
321 return ct->ct_error.re_status;
325 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
327 struct ct_data *ct = (struct ct_data *) h->cl_private;
329 *errp = ct->ct_error;
333 clntunix_freeres (cl, xdr_res, res_ptr)
338 struct ct_data *ct = (struct ct_data *) cl->cl_private;
339 XDR *xdrs = &(ct->ct_xdrs);
341 xdrs->x_op = XDR_FREE;
342 return (*xdr_res) (xdrs, res_ptr);
351 clntunix_control (CLIENT *cl, int request, char *info)
353 struct ct_data *ct = (struct ct_data *) cl->cl_private;
359 ct->ct_closeit = TRUE;
361 case CLSET_FD_NCLOSE:
362 ct->ct_closeit = FALSE;
365 ct->ct_wait = *(struct timeval *) info;
368 *(struct timeval *) info = ct->ct_wait;
370 case CLGET_SERVER_ADDR:
371 *(struct sockaddr_un *) info = ct->ct_addr;
374 *(int *)info = ct->ct_sock;
378 * use the knowledge that xid is the
379 * first element in the call structure *.
380 * This will get the xid of the PREVIOUS call
382 *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
385 /* This will set the xid of the NEXT call */
386 *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
387 /* decrement by 1 as clntunix_call() increments once */
390 * This RELIES on the information that, in the call body,
391 * the version number field is the fifth field from the
392 * begining of the RPC header. MUST be changed if the
393 * call_struct is changed
395 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
396 + 4 * BYTES_PER_XDR_UNIT));
399 *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
400 = htonl (*(u_long *) info);
404 * This RELIES on the information that, in the call body,
405 * the program number field is the field from the
406 * begining of the RPC header. MUST be changed if the
407 * call_struct is changed
409 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
410 + 3 * BYTES_PER_XDR_UNIT));
413 *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
414 = htonl(*(u_long *) info);
416 /* The following are only possible with TI-RPC */
417 case CLGET_RETRY_TIMEOUT:
418 case CLSET_RETRY_TIMEOUT:
421 case CLSET_PUSH_TIMOD:
422 case CLSET_POP_TIMOD:
431 clntunix_destroy (CLIENT *h)
434 (struct ct_data *) h->cl_private;
438 (void) close (ct->ct_sock);
440 XDR_DESTROY (&(ct->ct_xdrs));
441 mem_free ((caddr_t) ct, sizeof (struct ct_data));
442 mem_free ((caddr_t) h, sizeof (CLIENT));
446 __msgread (int sock, void *data, size_t cnt)
450 #ifdef SCM_CREDENTIALS
451 /*static -why??*/ char cm[CMSG_SPACE(sizeof (struct ucred))];
462 #ifdef SCM_CREDENTIALS
463 msg.msg_control = (caddr_t) &cm;
464 msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
471 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
477 len = recvmsg (sock, &msg, 0);
480 if (msg.msg_flags & MSG_CTRUNC || len == 0)
491 __msgwrite (int sock, void *data, size_t cnt)
493 #ifndef SCM_CREDENTIALS
494 /* We cannot implement this reliably. */
495 __set_errno (ENOSYS);
500 struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
504 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
505 get?id(). But since keyserv needs geteuid(), we have no other chance.
506 It would be much better, if the kernel could pass both to the server. */
507 cred.pid = getpid ();
508 cred.uid = geteuid ();
509 cred.gid = getegid ();
511 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
512 cmsg->cmsg_level = SOL_SOCKET;
513 cmsg->cmsg_type = SCM_CREDENTIALS;
514 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
523 msg.msg_control = cmsg;
524 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
528 len = sendmsg (sock, &msg, 0);
540 * Interface between xdr serializer and unix connection.
541 * Behaves like the system calls, read & write, but keeps some error state
542 * around for the rpc level.
545 readunix (char *ctptr, char *buf, int len)
547 struct ct_data *ct = (struct ct_data *) ctptr;
549 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
550 + (ct->ct_wait.tv_usec / 1000));
559 switch (poll (&fd, 1, milliseconds))
562 ct->ct_error.re_status = RPC_TIMEDOUT;
568 ct->ct_error.re_status = RPC_CANTRECV;
569 ct->ct_error.re_errno = errno;
574 switch (len = __msgread (ct->ct_sock, buf, len))
579 ct->ct_error.re_errno = ECONNRESET;
580 ct->ct_error.re_status = RPC_CANTRECV;
581 len = -1; /* it's really an error */
585 ct->ct_error.re_errno = errno;
586 ct->ct_error.re_status = RPC_CANTRECV;
593 writeunix (char *ctptr, char *buf, int len)
596 struct ct_data *ct = (struct ct_data *) ctptr;
598 for (cnt = len; cnt > 0; cnt -= i, buf += i)
600 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
602 ct->ct_error.re_errno = errno;
603 ct->ct_error.re_status = RPC_CANTSEND;