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