Update.
[glibc.git] / sunrpc / clnt_unix.c
blob211fcd6f7940a59073eae7afae78c4eff93486d8
1 /*
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.
26 * 2550 Garcia Avenue
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.
49 #include <netdb.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <libintl.h>
54 #include <rpc/rpc.h>
55 #include <sys/uio.h>
56 #include <sys/poll.h>
57 #include <sys/socket.h>
58 #include <rpc/pmap_clnt.h>
60 extern u_long _create_xid (void);
62 #define MCALL_MSG_SIZE 24
64 struct ct_data
66 int ct_sock;
67 bool_t ct_closeit;
68 struct timeval ct_wait;
69 bool_t ct_waitset; /* wait set by clnt_control? */
70 struct sockaddr_un ct_addr;
71 struct rpc_err ct_error;
72 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
73 u_int ct_mpos; /* pos after marshal */
74 XDR ct_xdrs;
77 static int readunix (char *, char *, int);
78 static int writeunix (char *, char *, int);
80 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
81 xdrproc_t, caddr_t, struct timeval);
82 static void clntunix_abort (void);
83 static void clntunix_geterr (CLIENT *, struct rpc_err *);
84 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
85 static bool_t clntunix_control (CLIENT *, int, char *);
86 static void clntunix_destroy (CLIENT *);
88 static struct clnt_ops unix_ops =
90 clntunix_call,
91 clntunix_abort,
92 clntunix_geterr,
93 clntunix_freeres,
94 clntunix_destroy,
95 clntunix_control
99 * Create a client handle for a tcp/ip connection.
100 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
101 * connected to raddr. If *sockp non-negative then
102 * raddr is ignored. The rpc/tcp package does buffering
103 * similar to stdio, so the client must pick send and receive buffer sizes,];
104 * 0 => use the default.
105 * If raddr->sin_port is 0, then a binder on the remote machine is
106 * consulted for the right port number.
107 * NB: *sockp is copied into a private area.
108 * NB: It is the clients responsibility to close *sockp.
109 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
110 * something more useful.
112 CLIENT *
113 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
114 int *sockp, u_int sendsz, u_int recvsz)
116 CLIENT *h;
117 struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
118 struct rpc_msg call_msg;
119 int len;
121 h = (CLIENT *) mem_alloc (sizeof (*h));
122 if (h == NULL)
124 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
125 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
126 rpc_createerr.cf_error.re_errno = errno;
127 goto fooy;
129 /* ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
130 if (ct == NULL)
132 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
133 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
134 rpc_createerr.cf_error.re_errno = errno;
135 goto fooy;
139 * If no socket given, open one
141 if (*sockp < 0)
143 *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
144 len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
145 if (*sockp < 0
146 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
148 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
149 rpc_createerr.cf_error.re_errno = errno;
150 if (*sockp != -1)
151 __close (*sockp);
152 goto fooy;
154 ct->ct_closeit = TRUE;
156 else
158 ct->ct_closeit = FALSE;
162 * Set up private data struct
164 ct->ct_sock = *sockp;
165 ct->ct_wait.tv_usec = 0;
166 ct->ct_waitset = FALSE;
167 ct->ct_addr = *raddr;
170 * Initialize call message
172 call_msg.rm_xid = _create_xid ();
173 call_msg.rm_direction = CALL;
174 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
175 call_msg.rm_call.cb_prog = prog;
176 call_msg.rm_call.cb_vers = vers;
179 * pre-serialize the static part of the call msg and stash it away
181 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
182 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
184 if (ct->ct_closeit)
185 __close (*sockp);
186 goto fooy;
188 ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
189 XDR_DESTROY (&(ct->ct_xdrs));
192 * Create a client handle which uses xdrrec for serialization
193 * and authnone for authentication.
195 xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
196 (caddr_t) ct, readunix, writeunix);
197 h->cl_ops = &unix_ops;
198 h->cl_private = (caddr_t) ct;
199 h->cl_auth = authnone_create ();
200 return h;
202 fooy:
204 * Something goofed, free stuff and barf
206 mem_free ((caddr_t) ct, sizeof (struct ct_data));
207 mem_free ((caddr_t) h, sizeof (CLIENT));
208 return (CLIENT *) NULL;
211 static enum clnt_stat
212 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
213 CLIENT *h;
214 u_long proc;
215 xdrproc_t xdr_args;
216 caddr_t args_ptr;
217 xdrproc_t xdr_results;
218 caddr_t results_ptr;
219 struct timeval timeout;
221 struct ct_data *ct = (struct ct_data *) h->cl_private;
222 XDR *xdrs = &(ct->ct_xdrs);
223 struct rpc_msg reply_msg;
224 u_long x_id;
225 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
226 bool_t shipnow;
227 int refreshes = 2;
229 if (!ct->ct_waitset)
231 ct->ct_wait = timeout;
234 shipnow =
235 (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
236 && timeout.tv_usec == 0) ? FALSE : TRUE;
238 call_again:
239 xdrs->x_op = XDR_ENCODE;
240 ct->ct_error.re_status = RPC_SUCCESS;
241 x_id = ntohl (--(*msg_x_id));
242 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
243 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
244 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
245 (!(*xdr_args) (xdrs, args_ptr)))
247 if (ct->ct_error.re_status == RPC_SUCCESS)
248 ct->ct_error.re_status = RPC_CANTENCODEARGS;
249 (void) xdrrec_endofrecord (xdrs, TRUE);
250 return ct->ct_error.re_status;
252 if (!xdrrec_endofrecord (xdrs, shipnow))
253 return ct->ct_error.re_status = RPC_CANTSEND;
254 if (!shipnow)
255 return RPC_SUCCESS;
257 * Hack to provide rpc-based message passing
259 if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
260 return ct->ct_error.re_status = RPC_TIMEDOUT;
264 * Keep receiving until we get a valid transaction id
266 xdrs->x_op = XDR_DECODE;
267 while (TRUE)
269 reply_msg.acpted_rply.ar_verf = _null_auth;
270 reply_msg.acpted_rply.ar_results.where = NULL;
271 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
272 if (!xdrrec_skiprecord (xdrs))
273 return ct->ct_error.re_status;
274 /* now decode and validate the response header */
275 if (!xdr_replymsg (xdrs, &reply_msg))
277 if (ct->ct_error.re_status == RPC_SUCCESS)
278 continue;
279 return ct->ct_error.re_status;
281 if (reply_msg.rm_xid == x_id)
282 break;
286 * process header
288 _seterr_reply (&reply_msg, &(ct->ct_error));
289 if (ct->ct_error.re_status == RPC_SUCCESS)
291 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
293 ct->ct_error.re_status = RPC_AUTHERROR;
294 ct->ct_error.re_why = AUTH_INVALIDRESP;
296 else if (!(*xdr_results) (xdrs, results_ptr))
298 if (ct->ct_error.re_status == RPC_SUCCESS)
299 ct->ct_error.re_status = RPC_CANTDECODERES;
301 /* free verifier ... */
302 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
304 xdrs->x_op = XDR_FREE;
305 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
307 } /* end successful completion */
308 else
310 /* maybe our credentials need to be refreshed ... */
311 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
312 goto call_again;
313 } /* end of unsuccessful completion */
314 return ct->ct_error.re_status;
317 static void
318 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
320 struct ct_data *ct = (struct ct_data *) h->cl_private;
322 *errp = ct->ct_error;
325 static bool_t
326 clntunix_freeres (cl, xdr_res, res_ptr)
327 CLIENT *cl;
328 xdrproc_t xdr_res;
329 caddr_t res_ptr;
331 struct ct_data *ct = (struct ct_data *) cl->cl_private;
332 XDR *xdrs = &(ct->ct_xdrs);
334 xdrs->x_op = XDR_FREE;
335 return (*xdr_res) (xdrs, res_ptr);
338 static void
339 clntunix_abort ()
343 static bool_t
344 clntunix_control (CLIENT *cl, int request, char *info)
346 struct ct_data *ct = (struct ct_data *) cl->cl_private;
349 switch (request)
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:
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
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 case CLGET_VERS:
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
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:
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
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;
419 return TRUE;
423 static void
424 clntunix_destroy (CLIENT *h)
426 struct ct_data *ct =
427 (struct ct_data *) h->cl_private;
429 if (ct->ct_closeit)
431 (void) __close (ct->ct_sock);
433 XDR_DESTROY (&(ct->ct_xdrs));
434 mem_free ((caddr_t) ct, sizeof (struct ct_data));
435 mem_free ((caddr_t) h, sizeof (CLIENT));
438 static int
439 __msgread (int sock, void *data, size_t cnt)
441 struct iovec iov;
442 struct msghdr msg;
443 #ifdef SCM_CREDENTIALS
444 static char cm[CMSG_SPACE(sizeof (struct ucred))];
445 #endif
446 int len;
448 iov.iov_base = data;
449 iov.iov_len = cnt;
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;
461 #ifdef SO_PASSCRED
463 int on = 1;
464 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
465 return -1;
467 #endif
469 restart:
470 len = recvmsg (sock, &msg, 0);
471 if (len >= 0)
473 if (msg.msg_flags & MSG_CTRUNC || len == 0)
474 return 0;
475 else
476 return len;
478 if (errno == EINTR)
479 goto restart;
480 return -1;
483 static int
484 __msgwrite (int sock, void *data, size_t cnt)
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;
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 ();
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);
509 iov.iov_base = data;
510 iov.iov_len = cnt;
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;
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;
528 #endif
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.
537 static int
538 readunix (char *ctptr, char *buf, int len)
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));
545 if (len == 0)
546 return 0;
548 fd.fd = ct->ct_sock;
549 fd.events = POLLIN;
550 while (TRUE)
552 switch (__poll (&fd, 1, milliseconds))
554 case 0:
555 ct->ct_error.re_status = RPC_TIMEDOUT;
556 return -1;
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;
565 break;
567 switch (len = __msgread (ct->ct_sock, buf, len))
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;
577 case -1:
578 ct->ct_error.re_errno = errno;
579 ct->ct_error.re_status = RPC_CANTRECV;
580 break;
582 return len;
585 static int
586 writeunix (char *ctptr, char *buf, int len)
588 int i, cnt;
589 struct ct_data *ct = (struct ct_data *) ctptr;
591 for (cnt = len; cnt > 0; cnt -= i, buf += i)
593 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
595 ct->ct_error.re_errno = errno;
596 ct->ct_error.re_status = RPC_CANTSEND;
597 return -1;
600 return len;