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 * svc_unix.c, Server side for TCP/IP based RPC.
33 * Copyright (C) 1984, Sun Microsystems, Inc.
35 * Actually implements two flavors of transporter -
36 * a unix rendezvouser (a listener and connection establisher)
37 * and a record/unix stream.
45 #include <sys/socket.h>
57 * Ops vector for AF_UNIX based rpc service handle
59 static bool_t
svcunix_recv (SVCXPRT
*, struct rpc_msg
*);
60 static enum xprt_stat
svcunix_stat (SVCXPRT
*);
61 static bool_t
svcunix_getargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
62 static bool_t
svcunix_reply (SVCXPRT
*, struct rpc_msg
*);
63 static bool_t
svcunix_freeargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
64 static void svcunix_destroy (SVCXPRT
*);
66 static const struct xp_ops svcunix_op
=
77 * Ops vector for AF_UNIX rendezvous handler
79 static bool_t
rendezvous_request (SVCXPRT
*, struct rpc_msg
*);
80 static enum xprt_stat
rendezvous_stat (SVCXPRT
*);
81 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__
));
83 /* This function makes sure abort() relocation goes through PLT
84 and thus can be lazy bound. */
86 svcunix_rendezvous_abort (void)
91 static const struct xp_ops svcunix_rendezvous_op
=
95 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) svcunix_rendezvous_abort
,
96 (bool_t (*) (SVCXPRT
*, struct rpc_msg
*)) svcunix_rendezvous_abort
,
97 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) svcunix_rendezvous_abort
,
101 static int readunix (char*, char *, int);
102 static int writeunix (char *, char *, int);
103 static SVCXPRT
*makefd_xprt (int, u_int
, u_int
) internal_function
;
105 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
110 struct unix_conn
{ /* kept in xprt->xp_p1 */
111 enum xprt_stat strm_stat
;
114 char verf_body
[MAX_AUTH_BYTES
];
119 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
121 * Creates, registers, and returns a (rpc) unix based transporter.
122 * Once *xprt is initialized, it is registered as a transporter
123 * see (svc.h, xprt_register). This routine returns
124 * a NULL if a problem occurred.
126 * If sock<0 then a socket is created, else sock is used.
127 * If the socket, sock is not bound to a port then svcunix_create
128 * binds it to an arbitrary port. The routine then starts a unix
129 * listener on the socket's associated port. In any (successful) case,
130 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
131 * associated port number.
133 * Since unix streams do buffered io similar to stdio, the caller can specify
134 * how big the send and receive buffers are via the second and third parms;
135 * 0 => use the system default.
138 svcunix_create (int sock
, u_int sendsize
, u_int recvsize
, char *path
)
140 bool_t madesock
= FALSE
;
142 struct unix_rendezvous
*r
;
143 struct sockaddr_un addr
;
144 socklen_t len
= sizeof (struct sockaddr_in
);
146 if (sock
== RPC_ANYSOCK
)
148 if ((sock
= __socket (AF_UNIX
, SOCK_STREAM
, 0)) < 0)
150 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
151 return (SVCXPRT
*) NULL
;
155 memset (&addr
, '\0', sizeof (addr
));
156 addr
.sun_family
= AF_UNIX
;
157 len
= strlen (path
) + 1;
158 memcpy (addr
.sun_path
, path
, len
);
159 len
+= sizeof (addr
.sun_family
);
161 __bind (sock
, (struct sockaddr
*) &addr
, len
);
163 if (__getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0
164 || __listen (sock
, SOMAXCONN
) != 0)
166 perror (_("svc_unix.c - cannot getsockname or listen"));
169 return (SVCXPRT
*) NULL
;
172 r
= (struct unix_rendezvous
*) mem_alloc (sizeof (*r
));
173 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
174 if (r
== NULL
|| xprt
== NULL
)
176 __fxprintf (NULL
, "%s: %s", __func__
, _("out of memory\n"));
177 mem_free (r
, sizeof (*r
));
178 mem_free (xprt
, sizeof (SVCXPRT
));
181 r
->sendsize
= sendsize
;
182 r
->recvsize
= recvsize
;
184 xprt
->xp_p1
= (caddr_t
) r
;
185 xprt
->xp_verf
= _null_auth
;
186 xprt
->xp_ops
= &svcunix_rendezvous_op
;
188 xprt
->xp_sock
= sock
;
189 xprt_register (xprt
);
194 * Like svunix_create(), except the routine takes any *open* UNIX file
195 * descriptor as its first input.
198 svcunixfd_create (int fd
, u_int sendsize
, u_int recvsize
)
200 return makefd_xprt (fd
, sendsize
, recvsize
);
205 makefd_xprt (int fd
, u_int sendsize
, u_int recvsize
)
208 struct unix_conn
*cd
;
210 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
211 cd
= (struct unix_conn
*) mem_alloc (sizeof (struct unix_conn
));
212 if (xprt
== (SVCXPRT
*) NULL
|| cd
== (struct unix_conn
*) NULL
)
214 (void) __fxprintf (NULL
, "%s: %s", "svc_unix: makefd_xprt",
215 _("out of memory\n"));
216 mem_free (xprt
, sizeof (SVCXPRT
));
217 mem_free (cd
, sizeof (struct unix_conn
));
220 cd
->strm_stat
= XPRT_IDLE
;
221 INTUSE(xdrrec_create
) (&(cd
->xdrs
), sendsize
, recvsize
,
222 (caddr_t
) xprt
, readunix
, writeunix
);
224 xprt
->xp_p1
= (caddr_t
) cd
;
225 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
226 xprt
->xp_addrlen
= 0;
227 xprt
->xp_ops
= &svcunix_op
; /* truly deals with calls */
228 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
230 xprt_register (xprt
);
235 rendezvous_request (SVCXPRT
*xprt
, struct rpc_msg
*errmsg
)
238 struct unix_rendezvous
*r
;
239 struct sockaddr_un addr
;
240 struct sockaddr_in in_addr
;
243 r
= (struct unix_rendezvous
*) xprt
->xp_p1
;
245 len
= sizeof (struct sockaddr_un
);
246 if ((sock
= accept (xprt
->xp_sock
, (struct sockaddr
*) &addr
, &len
)) < 0)
253 * make a new transporter (re-uses xprt)
255 memset (&in_addr
, '\0', sizeof (in_addr
));
256 in_addr
.sin_family
= AF_UNIX
;
257 xprt
= makefd_xprt (sock
, r
->sendsize
, r
->recvsize
);
258 memcpy (&xprt
->xp_raddr
, &in_addr
, sizeof (in_addr
));
259 xprt
->xp_addrlen
= len
;
260 return FALSE
; /* there is never an rpc msg to be processed */
263 static enum xprt_stat
264 rendezvous_stat (SVCXPRT
*xprt
)
270 svcunix_destroy (SVCXPRT
*xprt
)
272 struct unix_conn
*cd
= (struct unix_conn
*) xprt
->xp_p1
;
274 xprt_unregister (xprt
);
275 __close (xprt
->xp_sock
);
276 if (xprt
->xp_port
!= 0)
278 /* a rendezvouser socket */
283 /* an actual connection socket */
284 XDR_DESTROY (&(cd
->xdrs
));
286 mem_free ((caddr_t
) cd
, sizeof (struct unix_conn
));
287 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
290 #ifdef SCM_CREDENTIALS
294 /* hack to make sure we have enough memory */
295 char dummy
[(CMSG_ALIGN (sizeof (struct ucred
)) - sizeof (struct ucred
) + sizeof (long))];
298 /* XXX This is not thread safe, but since the main functions in svc.c
299 and the rpcgen generated *_svc functions for the daemon are also not
300 thread safe and uses static global variables, it doesn't matter. */
301 static struct cmessage cm
;
305 __msgread (int sock
, void *data
, size_t cnt
)
318 #ifdef SCM_CREDENTIALS
319 msg
.msg_control
= (caddr_t
) &cm
;
320 msg
.msg_controllen
= sizeof (struct cmessage
);
327 if (__setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
333 len
= __recvmsg (sock
, &msg
, 0);
336 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
347 __msgwrite (int sock
, void *data
, size_t cnt
)
349 #ifndef SCM_CREDENTIALS
350 /* We cannot implement this reliably. */
351 __set_errno (ENOSYS
);
356 struct cmsghdr
*cmsg
= &cm
.cmsg
;
360 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
361 get?id(). But since keyserv needs geteuid(), we have no other chance.
362 It would be much better, if the kernel could pass both to the server. */
363 cred
.pid
= __getpid ();
364 cred
.uid
= __geteuid ();
365 cred
.gid
= __getegid ();
367 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
368 cmsg
->cmsg_level
= SOL_SOCKET
;
369 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
370 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
379 msg
.msg_control
= cmsg
;
380 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
384 len
= __sendmsg (sock
, &msg
, 0);
395 * reads data from the unix connection.
396 * any error is fatal and the connection is closed.
397 * (And a read of zero bytes is a half closed stream => error.)
400 readunix (char *xprtptr
, char *buf
, int len
)
402 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
403 int sock
= xprt
->xp_sock
;
404 int milliseconds
= 35 * 1000;
405 struct pollfd pollfd
;
410 pollfd
.events
= POLLIN
;
411 switch (__poll (&pollfd
, 1, milliseconds
))
420 if ((pollfd
.revents
& POLLERR
) || (pollfd
.revents
& POLLHUP
)
421 || (pollfd
.revents
& POLLNVAL
))
426 while ((pollfd
.revents
& POLLIN
) == 0);
428 if ((len
= __msgread (sock
, buf
, len
)) > 0)
432 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
437 * writes data to the unix connection.
438 * Any error is fatal and the connection is closed.
441 writeunix (char *xprtptr
, char * buf
, int len
)
443 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
446 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
448 if ((i
= __msgwrite (xprt
->xp_sock
, buf
, cnt
)) < 0)
450 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
457 static enum xprt_stat
458 svcunix_stat (SVCXPRT
*xprt
)
460 struct unix_conn
*cd
=
461 (struct unix_conn
*) (xprt
->xp_p1
);
463 if (cd
->strm_stat
== XPRT_DIED
)
465 if (!INTUSE(xdrrec_eof
) (&(cd
->xdrs
)))
466 return XPRT_MOREREQS
;
471 svcunix_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
473 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
474 XDR
*xdrs
= &(cd
->xdrs
);
476 xdrs
->x_op
= XDR_DECODE
;
477 INTUSE(xdrrec_skiprecord
) (xdrs
);
478 if (INTUSE(xdr_callmsg
) (xdrs
, msg
))
480 cd
->x_id
= msg
->rm_xid
;
481 /* set up verifiers */
482 #ifdef SCM_CREDENTIALS
483 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
484 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
) &cm
;
485 msg
->rm_call
.cb_verf
.oa_length
= sizeof (cm
);
489 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
494 svcunix_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
496 return (*xdr_args
) (&(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
),
501 svcunix_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
503 XDR
*xdrs
= &(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
);
505 xdrs
->x_op
= XDR_FREE
;
506 return (*xdr_args
) (xdrs
, args_ptr
);
510 svcunix_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
512 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
513 XDR
*xdrs
= &(cd
->xdrs
);
516 xdrs
->x_op
= XDR_ENCODE
;
517 msg
->rm_xid
= cd
->x_id
;
518 stat
= INTUSE(xdr_replymsg
) (xdrs
, msg
);
519 (void) INTUSE(xdrrec_endofrecord
) (xdrs
, TRUE
);