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