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.
44 #include <sys/socket.h>
52 * Ops vector for AF_UNIX based rpc service handle
54 static bool_t
svcunix_recv (SVCXPRT
*, struct rpc_msg
*);
55 static enum xprt_stat
svcunix_stat (SVCXPRT
*);
56 static bool_t
svcunix_getargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
57 static bool_t
svcunix_reply (SVCXPRT
*, struct rpc_msg
*);
58 static bool_t
svcunix_freeargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
59 static void svcunix_destroy (SVCXPRT
*);
61 static const struct xp_ops svcunix_op
=
72 * Ops vector for AF_UNIX rendezvous handler
74 static bool_t
rendezvous_request (SVCXPRT
*, struct rpc_msg
*);
75 static enum xprt_stat
rendezvous_stat (SVCXPRT
*);
77 static const struct xp_ops svcunix_rendezvous_op
=
81 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
82 (bool_t (*) (SVCXPRT
*, struct rpc_msg
*)) abort
,
83 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
87 static int readunix (char*, char *, int);
88 static int writeunix (char *, char *, int);
89 static SVCXPRT
*makefd_xprt (int, u_int
, u_int
) internal_function
;
91 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
96 struct unix_conn
{ /* kept in xprt->xp_p1 */
97 enum xprt_stat strm_stat
;
100 char verf_body
[MAX_AUTH_BYTES
];
105 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
107 * Creates, registers, and returns a (rpc) unix based transporter.
108 * Once *xprt is initialized, it is registered as a transporter
109 * see (svc.h, xprt_register). This routine returns
110 * a NULL if a problem occurred.
112 * If sock<0 then a socket is created, else sock is used.
113 * If the socket, sock is not bound to a port then svcunix_create
114 * binds it to an arbitrary port. The routine then starts a unix
115 * listener on the socket's associated port. In any (successful) case,
116 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
117 * associated port number.
119 * Since unix streams do buffered io similar to stdio, the caller can specify
120 * how big the send and receive buffers are via the second and third parms;
121 * 0 => use the system default.
124 svcunix_create (int sock
, u_int sendsize
, u_int recvsize
, char *path
)
126 bool_t madesock
= FALSE
;
128 struct unix_rendezvous
*r
;
129 struct sockaddr_un addr
;
130 socklen_t len
= sizeof (struct sockaddr_in
);
132 if (sock
== RPC_ANYSOCK
)
134 if ((sock
= __socket (AF_UNIX
, SOCK_STREAM
, 0)) < 0)
136 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
137 return (SVCXPRT
*) NULL
;
141 memset (&addr
, '\0', sizeof (addr
));
142 addr
.sun_family
= AF_UNIX
;
143 len
= strlen (path
) + 1;
144 memcpy (addr
.sun_path
, path
, len
);
145 len
+= sizeof (addr
.sun_family
);
147 bind (sock
, (struct sockaddr
*) &addr
, len
);
149 if (getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0
150 || listen (sock
, 2) != 0)
152 perror (_("svc_unix.c - cannot getsockname or listen"));
155 return (SVCXPRT
*) NULL
;
158 r
= (struct unix_rendezvous
*) mem_alloc (sizeof (*r
));
161 fputs (_("svcunix_create: out of memory\n"), stderr
);
164 r
->sendsize
= sendsize
;
165 r
->recvsize
= recvsize
;
166 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
169 fputs (_("svcunix_create: out of memory\n"), stderr
);
173 xprt
->xp_p1
= (caddr_t
) r
;
174 xprt
->xp_verf
= _null_auth
;
175 xprt
->xp_ops
= &svcunix_rendezvous_op
;
177 xprt
->xp_sock
= sock
;
178 xprt_register (xprt
);
183 * Like svunix_create(), except the routine takes any *open* UNIX file
184 * descriptor as its first input.
187 svcunixfd_create (int fd
, u_int sendsize
, u_int recvsize
)
189 return makefd_xprt (fd
, sendsize
, recvsize
);
194 makefd_xprt (int fd
, u_int sendsize
, u_int recvsize
)
197 struct unix_conn
*cd
;
199 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
200 if (xprt
== (SVCXPRT
*) NULL
)
202 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
205 cd
= (struct unix_conn
*) mem_alloc (sizeof (struct unix_conn
));
206 if (cd
== (struct unix_conn
*) NULL
)
208 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
209 mem_free ((char *) xprt
, sizeof (SVCXPRT
));
210 xprt
= (SVCXPRT
*) NULL
;
213 cd
->strm_stat
= XPRT_IDLE
;
214 xdrrec_create (&(cd
->xdrs
), sendsize
, recvsize
,
215 (caddr_t
) xprt
, readunix
, writeunix
);
217 xprt
->xp_p1
= (caddr_t
) cd
;
218 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
219 xprt
->xp_addrlen
= 0;
220 xprt
->xp_ops
= &svcunix_op
; /* truly deals with calls */
221 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
223 xprt_register (xprt
);
229 rendezvous_request (SVCXPRT
*xprt
, struct rpc_msg
*errmsg
)
232 struct unix_rendezvous
*r
;
233 struct sockaddr_un addr
;
234 struct sockaddr_in in_addr
;
237 r
= (struct unix_rendezvous
*) xprt
->xp_p1
;
239 len
= sizeof (struct sockaddr_un
);
240 if ((sock
= accept (xprt
->xp_sock
, (struct sockaddr
*) &addr
, &len
)) < 0)
247 * make a new transporter (re-uses xprt)
249 memset (&in_addr
, '\0', sizeof (in_addr
));
250 in_addr
.sin_family
= AF_UNIX
;
251 xprt
= makefd_xprt (sock
, r
->sendsize
, r
->recvsize
);
252 memcpy (&xprt
->xp_raddr
, &in_addr
, sizeof (in_addr
));
253 xprt
->xp_addrlen
= len
;
254 return FALSE
; /* there is never an rpc msg to be processed */
257 static enum xprt_stat
258 rendezvous_stat (SVCXPRT
*xprt
)
264 svcunix_destroy (SVCXPRT
*xprt
)
266 struct unix_conn
*cd
= (struct unix_conn
*) xprt
->xp_p1
;
268 xprt_unregister (xprt
);
269 __close (xprt
->xp_sock
);
270 if (xprt
->xp_port
!= 0)
272 /* a rendezvouser socket */
277 /* an actual connection socket */
278 XDR_DESTROY (&(cd
->xdrs
));
280 mem_free ((caddr_t
) cd
, sizeof (struct unix_conn
));
281 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
284 #ifdef SCM_CREDENTIALS
288 /* hack to make sure we have enough memory */
289 char dummy
[(CMSG_ALIGN (sizeof (struct ucred
)) - sizeof (struct ucred
) + sizeof (long))];
292 /* XXX This is not thread safe, but since the main functions in svc.c
293 and the rpcgen generated *_svc functions for the daemon are also not
294 thread safe and uses static global variables, it doesn't matter. */
295 static struct cmessage cm
;
299 __msgread (int sock
, void *data
, size_t cnt
)
312 #ifdef SCM_CREDENTIALS
313 msg
.msg_control
= (caddr_t
) &cm
;
314 msg
.msg_controllen
= sizeof (struct cmessage
);
321 if (setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
327 len
= recvmsg (sock
, &msg
, 0);
330 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
341 __msgwrite (int sock
, void *data
, size_t cnt
)
343 #ifndef SCM_CREDENTIALS
344 /* We cannot implement this reliably. */
345 __set_errno (ENOSYS
);
350 struct cmsghdr
*cmsg
= &cm
.cmsg
;
354 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
355 get?id(). But since keyserv needs geteuid(), we have no other chance.
356 It would be much better, if the kernel could pass both to the server. */
357 cred
.pid
= __getpid ();
358 cred
.uid
= __geteuid ();
359 cred
.gid
= __getegid ();
361 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
362 cmsg
->cmsg_level
= SOL_SOCKET
;
363 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
364 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
373 msg
.msg_control
= cmsg
;
374 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
378 len
= sendmsg (sock
, &msg
, 0);
389 * reads data from the unix connection.
390 * any error is fatal and the connection is closed.
391 * (And a read of zero bytes is a half closed stream => error.)
394 readunix (char *xprtptr
, char *buf
, int len
)
396 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
397 int sock
= xprt
->xp_sock
;
398 int milliseconds
= 35 * 1000;
399 struct pollfd pollfd
;
404 pollfd
.events
= POLLIN
;
405 switch (__poll (&pollfd
, 1, milliseconds
))
414 if ((pollfd
.revents
& POLLERR
) || (pollfd
.revents
& POLLHUP
)
415 || (pollfd
.revents
& POLLNVAL
))
420 while ((pollfd
.revents
& POLLIN
) == 0);
422 if ((len
= __msgread (sock
, buf
, len
)) > 0)
426 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
431 * writes data to the unix connection.
432 * Any error is fatal and the connection is closed.
435 writeunix (char *xprtptr
, char * buf
, int len
)
437 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
440 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
442 if ((i
= __msgwrite (xprt
->xp_sock
, buf
, cnt
)) < 0)
444 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
451 static enum xprt_stat
452 svcunix_stat (SVCXPRT
*xprt
)
454 struct unix_conn
*cd
=
455 (struct unix_conn
*) (xprt
->xp_p1
);
457 if (cd
->strm_stat
== XPRT_DIED
)
459 if (!xdrrec_eof (&(cd
->xdrs
)))
460 return XPRT_MOREREQS
;
465 svcunix_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
467 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
468 XDR
*xdrs
= &(cd
->xdrs
);
470 xdrs
->x_op
= XDR_DECODE
;
471 xdrrec_skiprecord (xdrs
);
472 if (xdr_callmsg (xdrs
, msg
))
474 cd
->x_id
= msg
->rm_xid
;
475 /* set up verifiers */
476 #ifdef SCM_CREDENTIALS
477 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
478 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
) &cm
;
479 msg
->rm_call
.cb_verf
.oa_length
= sizeof (cm
);
483 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
488 svcunix_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
490 return (*xdr_args
) (&(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
),
495 svcunix_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
497 XDR
*xdrs
= &(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
);
499 xdrs
->x_op
= XDR_FREE
;
500 return (*xdr_args
) (xdrs
, args_ptr
);
504 svcunix_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
506 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
507 XDR
*xdrs
= &(cd
->xdrs
);
510 xdrs
->x_op
= XDR_ENCODE
;
511 msg
->rm_xid
= cd
->x_id
;
512 stat
= xdr_replymsg (xdrs
, msg
);
513 (void) xdrrec_endofrecord (xdrs
, TRUE
);