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.
57 #include <sys/socket.h>
58 #include <rpc/pmap_clnt.h>
63 extern u_long
_create_xid (void);
65 #define MCALL_MSG_SIZE 24
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 */
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 const struct clnt_ops unix_ops
=
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.
116 clntunix_create (struct sockaddr_un
*raddr
, u_long prog
, u_long vers
,
117 int *sockp
, u_int sendsz
, u_int recvsz
)
120 struct ct_data
*ct
= (struct ct_data
*) mem_alloc (sizeof (*ct
));
121 struct rpc_msg call_msg
;
124 h
= (CLIENT
*) mem_alloc (sizeof (*h
));
125 if (h
== NULL
|| ct
== NULL
)
127 struct rpc_createerr
*ce
= &get_rpc_createerr ();
128 (void) __fxprintf (NULL
, "%s: %s", __func__
, _("out of memory\n"));
129 ce
->cf_stat
= RPC_SYSTEMERROR
;
130 ce
->cf_error
.re_errno
= ENOMEM
;
135 * If no socket given, open one
139 *sockp
= __socket (AF_UNIX
, SOCK_STREAM
, 0);
140 len
= strlen (raddr
->sun_path
) + sizeof (raddr
->sun_family
) + 1;
142 || __connect (*sockp
, (struct sockaddr
*) raddr
, len
) < 0)
144 struct rpc_createerr
*ce
= &get_rpc_createerr ();
145 ce
->cf_stat
= RPC_SYSTEMERROR
;
146 ce
->cf_error
.re_errno
= errno
;
151 ct
->ct_closeit
= TRUE
;
155 ct
->ct_closeit
= FALSE
;
159 * Set up private data struct
161 ct
->ct_sock
= *sockp
;
162 ct
->ct_wait
.tv_usec
= 0;
163 ct
->ct_waitset
= FALSE
;
164 ct
->ct_addr
= *raddr
;
167 * Initialize call message
169 call_msg
.rm_xid
= _create_xid ();
170 call_msg
.rm_direction
= CALL
;
171 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
172 call_msg
.rm_call
.cb_prog
= prog
;
173 call_msg
.rm_call
.cb_vers
= vers
;
176 * pre-serialize the static part of the call msg and stash it away
178 INTUSE(xdrmem_create
) (&(ct
->ct_xdrs
), ct
->ct_mcall
, MCALL_MSG_SIZE
,
180 if (!INTUSE(xdr_callhdr
) (&(ct
->ct_xdrs
), &call_msg
))
186 ct
->ct_mpos
= XDR_GETPOS (&(ct
->ct_xdrs
));
187 XDR_DESTROY (&(ct
->ct_xdrs
));
190 * Create a client handle which uses xdrrec for serialization
191 * and authnone for authentication.
193 INTUSE(xdrrec_create
) (&(ct
->ct_xdrs
), sendsz
, recvsz
,
194 (caddr_t
) ct
, readunix
, writeunix
);
195 h
->cl_ops
= (struct clnt_ops
*) &unix_ops
;
196 h
->cl_private
= (caddr_t
) ct
;
197 h
->cl_auth
= INTUSE(authnone_create
) ();
202 * Something goofed, free stuff and barf
204 mem_free ((caddr_t
) ct
, sizeof (struct ct_data
));
205 mem_free ((caddr_t
) h
, sizeof (CLIENT
));
206 return (CLIENT
*) NULL
;
208 INTDEF (clntunix_create
)
210 static enum clnt_stat
211 clntunix_call (h
, proc
, xdr_args
, args_ptr
, xdr_results
, results_ptr
, timeout
)
216 xdrproc_t xdr_results
;
218 struct timeval timeout
;
220 struct ct_data
*ct
= (struct ct_data
*) h
->cl_private
;
221 XDR
*xdrs
= &(ct
->ct_xdrs
);
222 struct rpc_msg reply_msg
;
224 u_int32_t
*msg_x_id
= (u_int32_t
*) (ct
->ct_mcall
); /* yuk */
230 ct
->ct_wait
= timeout
;
234 (xdr_results
== (xdrproc_t
) 0 && ct
->ct_wait
.tv_sec
== 0
235 && ct
->ct_wait
.tv_usec
== 0) ? FALSE
: TRUE
;
238 xdrs
->x_op
= XDR_ENCODE
;
239 ct
->ct_error
.re_status
= RPC_SUCCESS
;
240 x_id
= ntohl (--(*msg_x_id
));
241 if ((!XDR_PUTBYTES (xdrs
, ct
->ct_mcall
, ct
->ct_mpos
)) ||
242 (!XDR_PUTLONG (xdrs
, (long *) &proc
)) ||
243 (!AUTH_MARSHALL (h
->cl_auth
, xdrs
)) ||
244 (!(*xdr_args
) (xdrs
, args_ptr
)))
246 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
247 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
248 (void) INTUSE(xdrrec_endofrecord
) (xdrs
, TRUE
);
249 return ct
->ct_error
.re_status
;
251 if (!INTUSE(xdrrec_endofrecord
) (xdrs
, shipnow
))
252 return ct
->ct_error
.re_status
= RPC_CANTSEND
;
256 * Hack to provide rpc-based message passing
258 if (ct
->ct_wait
.tv_sec
== 0 && ct
->ct_wait
.tv_usec
== 0)
259 return ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
263 * Keep receiving until we get a valid transaction id
265 xdrs
->x_op
= XDR_DECODE
;
268 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
269 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
270 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)INTUSE(xdr_void
);
271 if (!INTUSE(xdrrec_skiprecord
) (xdrs
))
272 return ct
->ct_error
.re_status
;
273 /* now decode and validate the response header */
274 if (!INTUSE(xdr_replymsg
) (xdrs
, &reply_msg
))
276 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
278 return ct
->ct_error
.re_status
;
280 if (reply_msg
.rm_xid
== x_id
)
287 _seterr_reply (&reply_msg
, &(ct
->ct_error
));
288 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
290 if (!AUTH_VALIDATE (h
->cl_auth
, &reply_msg
.acpted_rply
.ar_verf
))
292 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
293 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
295 else if (!(*xdr_results
) (xdrs
, results_ptr
))
297 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
298 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
300 /* free verifier ... */
301 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
)
303 xdrs
->x_op
= XDR_FREE
;
304 (void) INTUSE(xdr_opaque_auth
) (xdrs
,
305 &(reply_msg
.acpted_rply
.ar_verf
));
307 } /* end successful completion */
310 /* maybe our credentials need to be refreshed ... */
311 if (refreshes
-- && AUTH_REFRESH (h
->cl_auth
))
313 } /* end of unsuccessful completion */
314 return ct
->ct_error
.re_status
;
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
;
326 clntunix_freeres (cl
, xdr_res
, 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
);
344 clntunix_control (CLIENT
*cl
, int request
, char *info
)
346 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
352 ct
->ct_closeit
= TRUE
;
354 case CLSET_FD_NCLOSE
:
355 ct
->ct_closeit
= FALSE
;
358 ct
->ct_wait
= *(struct timeval
*) info
;
361 *(struct timeval
*) info
= ct
->ct_wait
;
363 case CLGET_SERVER_ADDR
:
364 *(struct sockaddr_un
*) info
= ct
->ct_addr
;
367 *(int *)info
= ct
->ct_sock
;
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
);
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 */
384 * This RELIES on the information that, in the call body,
385 * the version number field is the fifth field from the
386 * begining of the RPC header. MUST be changed if the
387 * call_struct is changed
389 *(u_long
*) info
= ntohl (*(u_long
*) (ct
->ct_mcall
390 + 4 * BYTES_PER_XDR_UNIT
));
393 *(u_long
*) (ct
->ct_mcall
+ 4 * BYTES_PER_XDR_UNIT
)
394 = htonl (*(u_long
*) info
);
398 * This RELIES on the information that, in the call body,
399 * the program number field is the field from the
400 * begining of the RPC header. MUST be changed if the
401 * call_struct is changed
403 *(u_long
*) info
= ntohl (*(u_long
*) (ct
->ct_mcall
404 + 3 * BYTES_PER_XDR_UNIT
));
407 *(u_long
*) (ct
->ct_mcall
+ 3 * BYTES_PER_XDR_UNIT
)
408 = htonl(*(u_long
*) info
);
410 /* The following are only possible with TI-RPC */
411 case CLGET_RETRY_TIMEOUT
:
412 case CLSET_RETRY_TIMEOUT
:
415 case CLSET_PUSH_TIMOD
:
416 case CLSET_POP_TIMOD
:
425 clntunix_destroy (CLIENT
*h
)
428 (struct ct_data
*) h
->cl_private
;
432 (void) __close (ct
->ct_sock
);
434 XDR_DESTROY (&(ct
->ct_xdrs
));
435 mem_free ((caddr_t
) ct
, sizeof (struct ct_data
));
436 mem_free ((caddr_t
) h
, sizeof (CLIENT
));
440 __msgread (int sock
, void *data
, size_t cnt
)
444 #ifdef SCM_CREDENTIALS
445 static char cm
[CMSG_SPACE(sizeof (struct ucred
))];
456 #ifdef SCM_CREDENTIALS
457 msg
.msg_control
= (caddr_t
) &cm
;
458 msg
.msg_controllen
= CMSG_SPACE(sizeof (struct ucred
));
465 if (__setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
471 len
= __recvmsg (sock
, &msg
, 0);
474 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
485 __msgwrite (int sock
, void *data
, size_t cnt
)
487 #ifndef SCM_CREDENTIALS
488 /* We cannot implement this reliably. */
489 __set_errno (ENOSYS
);
494 struct cmsghdr
*cmsg
= alloca (CMSG_SPACE(sizeof (struct ucred
)));
498 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
499 get?id(). But since keyserv needs geteuid(), we have no other chance.
500 It would be much better, if the kernel could pass both to the server. */
501 cred
.pid
= __getpid ();
502 cred
.uid
= __geteuid ();
503 cred
.gid
= __getegid ();
505 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
506 cmsg
->cmsg_level
= SOL_SOCKET
;
507 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
508 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
517 msg
.msg_control
= cmsg
;
518 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
522 len
= __sendmsg (sock
, &msg
, 0);
534 * Interface between xdr serializer and unix connection.
535 * Behaves like the system calls, read & write, but keeps some error state
536 * around for the rpc level.
539 readunix (char *ctptr
, char *buf
, int len
)
541 struct ct_data
*ct
= (struct ct_data
*) ctptr
;
543 int milliseconds
= ((ct
->ct_wait
.tv_sec
* 1000)
544 + (ct
->ct_wait
.tv_usec
/ 1000));
553 switch (__poll (&fd
, 1, milliseconds
))
556 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
562 ct
->ct_error
.re_status
= RPC_CANTRECV
;
563 ct
->ct_error
.re_errno
= errno
;
568 switch (len
= __msgread (ct
->ct_sock
, buf
, len
))
573 ct
->ct_error
.re_errno
= ECONNRESET
;
574 ct
->ct_error
.re_status
= RPC_CANTRECV
;
575 len
= -1; /* it's really an error */
579 ct
->ct_error
.re_errno
= errno
;
580 ct
->ct_error
.re_status
= RPC_CANTRECV
;
587 writeunix (char *ctptr
, char *buf
, int len
)
590 struct ct_data
*ct
= (struct ct_data
*) ctptr
;
592 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
594 if ((i
= __msgwrite (ct
->ct_sock
, buf
, cnt
)) == -1)
596 ct
->ct_error
.re_errno
= errno
;
597 ct
->ct_error
.re_status
= RPC_CANTSEND
;