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>
53 * Ops vector for AF_UNIX based rpc service handle
55 static bool_t
svcunix_recv (SVCXPRT
*, struct rpc_msg
*);
56 static enum xprt_stat
svcunix_stat (SVCXPRT
*);
57 static bool_t
svcunix_getargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
58 static bool_t
svcunix_reply (SVCXPRT
*, struct rpc_msg
*);
59 static bool_t
svcunix_freeargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
60 static void svcunix_destroy (SVCXPRT
*);
62 static const struct xp_ops svcunix_op
=
73 * Ops vector for AF_UNIX rendezvous handler
75 static bool_t
rendezvous_request (SVCXPRT
*, struct rpc_msg
*);
76 static enum xprt_stat
rendezvous_stat (SVCXPRT
*);
77 static void svcunix_rendezvous_abort (void);
79 /* This function makes sure abort() relocation goes through PLT
80 and thus can be lazy bound. */
82 svcunix_rendezvous_abort (void)
87 static const struct xp_ops svcunix_rendezvous_op
=
91 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) svcunix_rendezvous_abort
,
92 (bool_t (*) (SVCXPRT
*, struct rpc_msg
*)) svcunix_rendezvous_abort
,
93 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) svcunix_rendezvous_abort
,
97 static int readunix (char*, char *, int);
98 static int writeunix (char *, char *, int);
99 static SVCXPRT
*makefd_xprt (int, u_int
, u_int
) internal_function
;
101 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
106 struct unix_conn
{ /* kept in xprt->xp_p1 */
107 enum xprt_stat strm_stat
;
110 char verf_body
[MAX_AUTH_BYTES
];
115 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
117 * Creates, registers, and returns a (rpc) unix based transporter.
118 * Once *xprt is initialized, it is registered as a transporter
119 * see (svc.h, xprt_register). This routine returns
120 * a NULL if a problem occurred.
122 * If sock<0 then a socket is created, else sock is used.
123 * If the socket, sock is not bound to a port then svcunix_create
124 * binds it to an arbitrary port. The routine then starts a unix
125 * listener on the socket's associated port. In any (successful) case,
126 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
127 * associated port number.
129 * Since unix streams do buffered io similar to stdio, the caller can specify
130 * how big the send and receive buffers are via the second and third parms;
131 * 0 => use the system default.
134 svcunix_create (int sock
, u_int sendsize
, u_int recvsize
, char *path
)
136 bool_t madesock
= FALSE
;
138 struct unix_rendezvous
*r
;
139 struct sockaddr_un addr
;
140 socklen_t len
= sizeof (struct sockaddr_in
);
142 if (sock
== RPC_ANYSOCK
)
144 if ((sock
= __socket (AF_UNIX
, SOCK_STREAM
, 0)) < 0)
146 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
147 return (SVCXPRT
*) NULL
;
151 memset (&addr
, '\0', sizeof (addr
));
152 addr
.sun_family
= AF_UNIX
;
153 len
= strlen (path
) + 1;
154 memcpy (addr
.sun_path
, path
, len
);
155 len
+= sizeof (addr
.sun_family
);
157 bind (sock
, (struct sockaddr
*) &addr
, len
);
159 if (getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0
160 || listen (sock
, 2) != 0)
162 perror (_("svc_unix.c - cannot getsockname or listen"));
165 return (SVCXPRT
*) NULL
;
168 r
= (struct unix_rendezvous
*) mem_alloc (sizeof (*r
));
171 fputs (_("svcunix_create: out of memory\n"), stderr
);
174 r
->sendsize
= sendsize
;
175 r
->recvsize
= recvsize
;
176 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
179 fputs (_("svcunix_create: out of memory\n"), stderr
);
183 xprt
->xp_p1
= (caddr_t
) r
;
184 xprt
->xp_verf
= _null_auth
;
185 xprt
->xp_ops
= &svcunix_rendezvous_op
;
187 xprt
->xp_sock
= sock
;
188 xprt_register (xprt
);
193 * Like svunix_create(), except the routine takes any *open* UNIX file
194 * descriptor as its first input.
197 svcunixfd_create (int fd
, u_int sendsize
, u_int recvsize
)
199 return makefd_xprt (fd
, sendsize
, recvsize
);
204 makefd_xprt (int fd
, u_int sendsize
, u_int recvsize
)
207 struct unix_conn
*cd
;
209 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
210 if (xprt
== (SVCXPRT
*) NULL
)
212 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
215 cd
= (struct unix_conn
*) mem_alloc (sizeof (struct unix_conn
));
216 if (cd
== (struct unix_conn
*) NULL
)
218 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
219 mem_free ((char *) xprt
, sizeof (SVCXPRT
));
220 xprt
= (SVCXPRT
*) NULL
;
223 cd
->strm_stat
= XPRT_IDLE
;
224 xdrrec_create (&(cd
->xdrs
), sendsize
, recvsize
,
225 (caddr_t
) xprt
, readunix
, writeunix
);
227 xprt
->xp_p1
= (caddr_t
) cd
;
228 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
229 xprt
->xp_addrlen
= 0;
230 xprt
->xp_ops
= &svcunix_op
; /* truly deals with calls */
231 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
233 xprt_register (xprt
);
239 rendezvous_request (SVCXPRT
*xprt
, struct rpc_msg
*errmsg
)
242 struct unix_rendezvous
*r
;
243 struct sockaddr_un addr
;
244 struct sockaddr_in in_addr
;
247 r
= (struct unix_rendezvous
*) xprt
->xp_p1
;
249 len
= sizeof (struct sockaddr_un
);
250 if ((sock
= accept (xprt
->xp_sock
, (struct sockaddr
*) &addr
, &len
)) < 0)
257 * make a new transporter (re-uses xprt)
259 memset (&in_addr
, '\0', sizeof (in_addr
));
260 in_addr
.sin_family
= AF_UNIX
;
261 xprt
= makefd_xprt (sock
, r
->sendsize
, r
->recvsize
);
262 memcpy (&xprt
->xp_raddr
, &in_addr
, sizeof (in_addr
));
263 xprt
->xp_addrlen
= len
;
264 return FALSE
; /* there is never an rpc msg to be processed */
267 static enum xprt_stat
268 rendezvous_stat (SVCXPRT
*xprt
)
274 svcunix_destroy (SVCXPRT
*xprt
)
276 struct unix_conn
*cd
= (struct unix_conn
*) xprt
->xp_p1
;
278 xprt_unregister (xprt
);
279 __close (xprt
->xp_sock
);
280 if (xprt
->xp_port
!= 0)
282 /* a rendezvouser socket */
287 /* an actual connection socket */
288 XDR_DESTROY (&(cd
->xdrs
));
290 mem_free ((caddr_t
) cd
, sizeof (struct unix_conn
));
291 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
294 #ifdef SCM_CREDENTIALS
298 /* hack to make sure we have enough memory */
299 char dummy
[(CMSG_ALIGN (sizeof (struct ucred
)) - sizeof (struct ucred
) + sizeof (long))];
302 /* XXX This is not thread safe, but since the main functions in svc.c
303 and the rpcgen generated *_svc functions for the daemon are also not
304 thread safe and uses static global variables, it doesn't matter. */
305 static struct cmessage cm
;
309 __msgread (int sock
, void *data
, size_t cnt
)
322 #ifdef SCM_CREDENTIALS
323 msg
.msg_control
= (caddr_t
) &cm
;
324 msg
.msg_controllen
= sizeof (struct cmessage
);
331 if (setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
337 len
= recvmsg (sock
, &msg
, 0);
340 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
351 __msgwrite (int sock
, void *data
, size_t cnt
)
353 #ifndef SCM_CREDENTIALS
354 /* We cannot implement this reliably. */
355 __set_errno (ENOSYS
);
360 struct cmsghdr
*cmsg
= &cm
.cmsg
;
364 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
365 get?id(). But since keyserv needs geteuid(), we have no other chance.
366 It would be much better, if the kernel could pass both to the server. */
367 cred
.pid
= __getpid ();
368 cred
.uid
= __geteuid ();
369 cred
.gid
= __getegid ();
371 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
372 cmsg
->cmsg_level
= SOL_SOCKET
;
373 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
374 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
383 msg
.msg_control
= cmsg
;
384 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
388 len
= sendmsg (sock
, &msg
, 0);
399 * reads data from the unix connection.
400 * any error is fatal and the connection is closed.
401 * (And a read of zero bytes is a half closed stream => error.)
404 readunix (char *xprtptr
, char *buf
, int len
)
406 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
407 int sock
= xprt
->xp_sock
;
408 int milliseconds
= 35 * 1000;
409 struct pollfd pollfd
;
414 pollfd
.events
= POLLIN
;
415 switch (__poll (&pollfd
, 1, milliseconds
))
424 if ((pollfd
.revents
& POLLERR
) || (pollfd
.revents
& POLLHUP
)
425 || (pollfd
.revents
& POLLNVAL
))
430 while ((pollfd
.revents
& POLLIN
) == 0);
432 if ((len
= __msgread (sock
, buf
, len
)) > 0)
436 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
441 * writes data to the unix connection.
442 * Any error is fatal and the connection is closed.
445 writeunix (char *xprtptr
, char * buf
, int len
)
447 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
450 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
452 if ((i
= __msgwrite (xprt
->xp_sock
, buf
, cnt
)) < 0)
454 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
461 static enum xprt_stat
462 svcunix_stat (SVCXPRT
*xprt
)
464 struct unix_conn
*cd
=
465 (struct unix_conn
*) (xprt
->xp_p1
);
467 if (cd
->strm_stat
== XPRT_DIED
)
469 if (!xdrrec_eof (&(cd
->xdrs
)))
470 return XPRT_MOREREQS
;
475 svcunix_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
477 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
478 XDR
*xdrs
= &(cd
->xdrs
);
480 xdrs
->x_op
= XDR_DECODE
;
481 xdrrec_skiprecord (xdrs
);
482 if (xdr_callmsg (xdrs
, msg
))
484 cd
->x_id
= msg
->rm_xid
;
485 /* set up verifiers */
486 #ifdef SCM_CREDENTIALS
487 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
488 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
) &cm
;
489 msg
->rm_call
.cb_verf
.oa_length
= sizeof (cm
);
493 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
498 svcunix_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
500 return (*xdr_args
) (&(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
),
505 svcunix_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
507 XDR
*xdrs
= &(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
);
509 xdrs
->x_op
= XDR_FREE
;
510 return (*xdr_args
) (xdrs
, args_ptr
);
514 svcunix_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
516 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
517 XDR
*xdrs
= &(cd
->xdrs
);
520 xdrs
->x_op
= XDR_ENCODE
;
521 msg
->rm_xid
= cd
->x_id
;
522 stat
= xdr_replymsg (xdrs
, msg
);
523 (void) xdrrec_endofrecord (xdrs
, TRUE
);