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
*);
78 static const struct xp_ops svcunix_rendezvous_op
=
82 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
83 (bool_t (*) (SVCXPRT
*, struct rpc_msg
*)) abort
,
84 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
88 static int readunix (char*, char *, int);
89 static int writeunix (char *, char *, int);
90 static SVCXPRT
*makefd_xprt (int, u_int
, u_int
) internal_function
;
92 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
97 struct unix_conn
{ /* kept in xprt->xp_p1 */
98 enum xprt_stat strm_stat
;
101 char verf_body
[MAX_AUTH_BYTES
];
106 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
108 * Creates, registers, and returns a (rpc) unix based transporter.
109 * Once *xprt is initialized, it is registered as a transporter
110 * see (svc.h, xprt_register). This routine returns
111 * a NULL if a problem occurred.
113 * If sock<0 then a socket is created, else sock is used.
114 * If the socket, sock is not bound to a port then svcunix_create
115 * binds it to an arbitrary port. The routine then starts a unix
116 * listener on the socket's associated port. In any (successful) case,
117 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
118 * associated port number.
120 * Since unix streams do buffered io similar to stdio, the caller can specify
121 * how big the send and receive buffers are via the second and third parms;
122 * 0 => use the system default.
125 svcunix_create (int sock
, u_int sendsize
, u_int recvsize
, char *path
)
127 bool_t madesock
= FALSE
;
129 struct unix_rendezvous
*r
;
130 struct sockaddr_un addr
;
131 socklen_t len
= sizeof (struct sockaddr_in
);
133 if (sock
== RPC_ANYSOCK
)
135 if ((sock
= __socket (AF_UNIX
, SOCK_STREAM
, 0)) < 0)
137 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
138 return (SVCXPRT
*) NULL
;
142 memset (&addr
, '\0', sizeof (addr
));
143 addr
.sun_family
= AF_UNIX
;
144 len
= strlen (path
) + 1;
145 memcpy (addr
.sun_path
, path
, len
);
146 len
+= sizeof (addr
.sun_family
);
148 bind (sock
, (struct sockaddr
*) &addr
, len
);
150 if (getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0
151 || listen (sock
, 2) != 0)
153 perror (_("svc_unix.c - cannot getsockname or listen"));
156 return (SVCXPRT
*) NULL
;
159 r
= (struct unix_rendezvous
*) mem_alloc (sizeof (*r
));
162 fputs (_("svcunix_create: out of memory\n"), stderr
);
165 r
->sendsize
= sendsize
;
166 r
->recvsize
= recvsize
;
167 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
170 fputs (_("svcunix_create: out of memory\n"), stderr
);
174 xprt
->xp_p1
= (caddr_t
) r
;
175 xprt
->xp_verf
= _null_auth
;
176 xprt
->xp_ops
= &svcunix_rendezvous_op
;
178 xprt
->xp_sock
= sock
;
179 xprt_register (xprt
);
184 * Like svunix_create(), except the routine takes any *open* UNIX file
185 * descriptor as its first input.
188 svcunixfd_create (int fd
, u_int sendsize
, u_int recvsize
)
190 return makefd_xprt (fd
, sendsize
, recvsize
);
195 makefd_xprt (int fd
, u_int sendsize
, u_int recvsize
)
198 struct unix_conn
*cd
;
200 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
201 if (xprt
== (SVCXPRT
*) NULL
)
203 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
206 cd
= (struct unix_conn
*) mem_alloc (sizeof (struct unix_conn
));
207 if (cd
== (struct unix_conn
*) NULL
)
209 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
210 mem_free ((char *) xprt
, sizeof (SVCXPRT
));
211 xprt
= (SVCXPRT
*) NULL
;
214 cd
->strm_stat
= XPRT_IDLE
;
215 xdrrec_create (&(cd
->xdrs
), sendsize
, recvsize
,
216 (caddr_t
) xprt
, readunix
, writeunix
);
218 xprt
->xp_p1
= (caddr_t
) cd
;
219 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
220 xprt
->xp_addrlen
= 0;
221 xprt
->xp_ops
= &svcunix_op
; /* truly deals with calls */
222 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
224 xprt_register (xprt
);
230 rendezvous_request (SVCXPRT
*xprt
, struct rpc_msg
*errmsg
)
233 struct unix_rendezvous
*r
;
234 struct sockaddr_un addr
;
235 struct sockaddr_in in_addr
;
238 r
= (struct unix_rendezvous
*) xprt
->xp_p1
;
240 len
= sizeof (struct sockaddr_un
);
241 if ((sock
= accept (xprt
->xp_sock
, (struct sockaddr
*) &addr
, &len
)) < 0)
248 * make a new transporter (re-uses xprt)
250 memset (&in_addr
, '\0', sizeof (in_addr
));
251 in_addr
.sin_family
= AF_UNIX
;
252 xprt
= makefd_xprt (sock
, r
->sendsize
, r
->recvsize
);
253 memcpy (&xprt
->xp_raddr
, &in_addr
, sizeof (in_addr
));
254 xprt
->xp_addrlen
= len
;
255 return FALSE
; /* there is never an rpc msg to be processed */
258 static enum xprt_stat
259 rendezvous_stat (SVCXPRT
*xprt
)
265 svcunix_destroy (SVCXPRT
*xprt
)
267 struct unix_conn
*cd
= (struct unix_conn
*) xprt
->xp_p1
;
269 xprt_unregister (xprt
);
270 __close (xprt
->xp_sock
);
271 if (xprt
->xp_port
!= 0)
273 /* a rendezvouser socket */
278 /* an actual connection socket */
279 XDR_DESTROY (&(cd
->xdrs
));
281 mem_free ((caddr_t
) cd
, sizeof (struct unix_conn
));
282 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
285 #ifdef SCM_CREDENTIALS
289 /* hack to make sure we have enough memory */
290 char dummy
[(CMSG_ALIGN (sizeof (struct ucred
)) - sizeof (struct ucred
) + sizeof (long))];
293 /* XXX This is not thread safe, but since the main functions in svc.c
294 and the rpcgen generated *_svc functions for the daemon are also not
295 thread safe and uses static global variables, it doesn't matter. */
296 static struct cmessage cm
;
300 __msgread (int sock
, void *data
, size_t cnt
)
313 #ifdef SCM_CREDENTIALS
314 msg
.msg_control
= (caddr_t
) &cm
;
315 msg
.msg_controllen
= sizeof (struct cmessage
);
322 if (setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
328 len
= recvmsg (sock
, &msg
, 0);
331 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
342 __msgwrite (int sock
, void *data
, size_t cnt
)
344 #ifndef SCM_CREDENTIALS
345 /* We cannot implement this reliably. */
346 __set_errno (ENOSYS
);
351 struct cmsghdr
*cmsg
= &cm
.cmsg
;
355 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
356 get?id(). But since keyserv needs geteuid(), we have no other chance.
357 It would be much better, if the kernel could pass both to the server. */
358 cred
.pid
= __getpid ();
359 cred
.uid
= __geteuid ();
360 cred
.gid
= __getegid ();
362 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
363 cmsg
->cmsg_level
= SOL_SOCKET
;
364 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
365 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
374 msg
.msg_control
= cmsg
;
375 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
379 len
= sendmsg (sock
, &msg
, 0);
390 * reads data from the unix connection.
391 * any error is fatal and the connection is closed.
392 * (And a read of zero bytes is a half closed stream => error.)
395 readunix (char *xprtptr
, char *buf
, int len
)
397 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
398 int sock
= xprt
->xp_sock
;
399 int milliseconds
= 35 * 1000;
400 struct pollfd pollfd
;
405 pollfd
.events
= POLLIN
;
406 switch (__poll (&pollfd
, 1, milliseconds
))
415 if ((pollfd
.revents
& POLLERR
) || (pollfd
.revents
& POLLHUP
)
416 || (pollfd
.revents
& POLLNVAL
))
421 while ((pollfd
.revents
& POLLIN
) == 0);
423 if ((len
= __msgread (sock
, buf
, len
)) > 0)
427 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
432 * writes data to the unix connection.
433 * Any error is fatal and the connection is closed.
436 writeunix (char *xprtptr
, char * buf
, int len
)
438 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
441 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
443 if ((i
= __msgwrite (xprt
->xp_sock
, buf
, cnt
)) < 0)
445 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
452 static enum xprt_stat
453 svcunix_stat (SVCXPRT
*xprt
)
455 struct unix_conn
*cd
=
456 (struct unix_conn
*) (xprt
->xp_p1
);
458 if (cd
->strm_stat
== XPRT_DIED
)
460 if (!xdrrec_eof (&(cd
->xdrs
)))
461 return XPRT_MOREREQS
;
466 svcunix_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
468 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
469 XDR
*xdrs
= &(cd
->xdrs
);
471 xdrs
->x_op
= XDR_DECODE
;
472 xdrrec_skiprecord (xdrs
);
473 if (xdr_callmsg (xdrs
, msg
))
475 cd
->x_id
= msg
->rm_xid
;
476 /* set up verifiers */
477 #ifdef SCM_CREDENTIALS
478 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
479 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
) &cm
;
480 msg
->rm_call
.cb_verf
.oa_length
= sizeof (cm
);
484 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
489 svcunix_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
491 return (*xdr_args
) (&(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
),
496 svcunix_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
498 XDR
*xdrs
= &(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
);
500 xdrs
->x_op
= XDR_FREE
;
501 return (*xdr_args
) (xdrs
, args_ptr
);
505 svcunix_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
507 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
508 XDR
*xdrs
= &(cd
->xdrs
);
511 xdrs
->x_op
= XDR_ENCODE
;
512 msg
->rm_xid
= cd
->x_id
;
513 stat
= xdr_replymsg (xdrs
, msg
);
514 (void) xdrrec_endofrecord (xdrs
, TRUE
);