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>
51 * Ops vector for AF_UNIX based rpc service handle
53 static bool_t
svcunix_recv (SVCXPRT
*, struct rpc_msg
*);
54 static enum xprt_stat
svcunix_stat (SVCXPRT
*);
55 static bool_t
svcunix_getargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
56 static bool_t
svcunix_reply (SVCXPRT
*, struct rpc_msg
*);
57 static bool_t
svcunix_freeargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
58 static void svcunix_destroy (SVCXPRT
*);
60 static const struct xp_ops svcunix_op
=
71 * Ops vector for AF_UNIX rendezvous handler
73 static bool_t
rendezvous_request (SVCXPRT
*, struct rpc_msg
*);
74 static enum xprt_stat
rendezvous_stat (SVCXPRT
*);
76 static const struct xp_ops svcunix_rendezvous_op
=
80 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
81 (bool_t (*) (SVCXPRT
*, struct rpc_msg
*)) abort
,
82 (bool_t (*) (SVCXPRT
*, xdrproc_t
, caddr_t
)) abort
,
86 static int readunix (char*, char *, int);
87 static int writeunix (char *, char *, int);
88 static SVCXPRT
*makefd_xprt (int, u_int
, u_int
) internal_function
;
90 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
95 struct unix_conn
{ /* kept in xprt->xp_p1 */
96 enum xprt_stat strm_stat
;
99 char verf_body
[MAX_AUTH_BYTES
];
104 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
106 * Creates, registers, and returns a (rpc) unix based transporter.
107 * Once *xprt is initialized, it is registered as a transporter
108 * see (svc.h, xprt_register). This routine returns
109 * a NULL if a problem occurred.
111 * If sock<0 then a socket is created, else sock is used.
112 * If the socket, sock is not bound to a port then svcunix_create
113 * binds it to an arbitrary port. The routine then starts a unix
114 * listener on the socket's associated port. In any (successful) case,
115 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
116 * associated port number.
118 * Since unix streams do buffered io similar to stdio, the caller can specify
119 * how big the send and receive buffers are via the second and third parms;
120 * 0 => use the system default.
123 svcunix_create (int sock
, u_int sendsize
, u_int recvsize
, char *path
)
125 bool_t madesock
= FALSE
;
127 struct unix_rendezvous
*r
;
128 struct sockaddr_un addr
;
129 socklen_t len
= sizeof (struct sockaddr_in
);
131 if (sock
== RPC_ANYSOCK
)
133 if ((sock
= __socket (AF_UNIX
, SOCK_STREAM
, 0)) < 0)
135 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
136 return (SVCXPRT
*) NULL
;
140 memset (&addr
, '\0', sizeof (addr
));
141 addr
.sun_family
= AF_UNIX
;
142 len
= strlen (path
) + 1;
143 memcpy (addr
.sun_path
, path
, len
);
144 len
+= sizeof (addr
.sun_family
);
146 bind (sock
, (struct sockaddr
*) &addr
, len
);
148 if (getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0
149 || listen (sock
, 2) != 0)
151 perror (_("svc_unix.c - cannot getsockname or listen"));
154 return (SVCXPRT
*) NULL
;
157 r
= (struct unix_rendezvous
*) mem_alloc (sizeof (*r
));
160 fputs (_("svcunix_create: out of memory\n"), stderr
);
163 r
->sendsize
= sendsize
;
164 r
->recvsize
= recvsize
;
165 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
168 fputs (_("svcunix_create: out of memory\n"), stderr
);
172 xprt
->xp_p1
= (caddr_t
) r
;
173 xprt
->xp_verf
= _null_auth
;
174 xprt
->xp_ops
= &svcunix_rendezvous_op
;
176 xprt
->xp_sock
= sock
;
177 xprt_register (xprt
);
182 * Like svunix_create(), except the routine takes any *open* UNIX file
183 * descriptor as its first input.
186 svcunixfd_create (int fd
, u_int sendsize
, u_int recvsize
)
188 return makefd_xprt (fd
, sendsize
, recvsize
);
193 makefd_xprt (int fd
, u_int sendsize
, u_int recvsize
)
196 struct unix_conn
*cd
;
198 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
199 if (xprt
== (SVCXPRT
*) NULL
)
201 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
204 cd
= (struct unix_conn
*) mem_alloc (sizeof (struct unix_conn
));
205 if (cd
== (struct unix_conn
*) NULL
)
207 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr
);
208 mem_free ((char *) xprt
, sizeof (SVCXPRT
));
209 xprt
= (SVCXPRT
*) NULL
;
212 cd
->strm_stat
= XPRT_IDLE
;
213 xdrrec_create (&(cd
->xdrs
), sendsize
, recvsize
,
214 (caddr_t
) xprt
, readunix
, writeunix
);
216 xprt
->xp_p1
= (caddr_t
) cd
;
217 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
218 xprt
->xp_addrlen
= 0;
219 xprt
->xp_ops
= &svcunix_op
; /* truly deals with calls */
220 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
222 xprt_register (xprt
);
228 rendezvous_request (SVCXPRT
*xprt
, struct rpc_msg
*errmsg
)
231 struct unix_rendezvous
*r
;
232 struct sockaddr_un addr
;
233 struct sockaddr_in in_addr
;
236 r
= (struct unix_rendezvous
*) xprt
->xp_p1
;
238 len
= sizeof (struct sockaddr_un
);
239 if ((sock
= accept (xprt
->xp_sock
, (struct sockaddr
*) &addr
, &len
)) < 0)
246 * make a new transporter (re-uses xprt)
248 memset (&in_addr
, '\0', sizeof (in_addr
));
249 in_addr
.sin_family
= AF_UNIX
;
250 xprt
= makefd_xprt (sock
, r
->sendsize
, r
->recvsize
);
251 xprt
->xp_raddr
= in_addr
;
252 xprt
->xp_addrlen
= len
;
253 return FALSE
; /* there is never an rpc msg to be processed */
256 static enum xprt_stat
257 rendezvous_stat (SVCXPRT
*xprt
)
263 svcunix_destroy (SVCXPRT
*xprt
)
265 struct unix_conn
*cd
= (struct unix_conn
*) xprt
->xp_p1
;
267 xprt_unregister (xprt
);
268 __close (xprt
->xp_sock
);
269 if (xprt
->xp_port
!= 0)
271 /* a rendezvouser socket */
276 /* an actual connection socket */
277 XDR_DESTROY (&(cd
->xdrs
));
279 mem_free ((caddr_t
) cd
, sizeof (struct unix_conn
));
280 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
283 #ifdef SCM_CREDENTIALS
287 /* hack to make sure we have enough memory */
288 char dummy
[(CMSG_ALIGN (sizeof (struct ucred
)) - sizeof (struct ucred
) + sizeof (long))];
291 /* XXX This is not thread safe, but since the main functions in svc.c
292 and the rpcgen generated *_svc functions for the daemon are also not
293 thread safe and uses static global variables, it doesn't matter. */
294 static struct cmessage cm
;
298 __msgread (int sock
, void *data
, size_t cnt
)
311 #ifdef SCM_CREDENTIALS
312 msg
.msg_control
= (caddr_t
) &cm
;
313 msg
.msg_controllen
= sizeof (struct cmessage
);
320 if (setsockopt (sock
, SOL_SOCKET
, SO_PASSCRED
, &on
, sizeof (on
)))
326 len
= recvmsg (sock
, &msg
, 0);
329 if (msg
.msg_flags
& MSG_CTRUNC
|| len
== 0)
340 __msgwrite (int sock
, void *data
, size_t cnt
)
342 #ifndef SCM_CREDENTIALS
343 /* We cannot implement this reliably. */
344 __set_errno (ENOSYS
);
349 struct cmsghdr
*cmsg
= &cm
.cmsg
;
353 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
354 get?id(). But since keyserv needs geteuid(), we have no other chance.
355 It would be much better, if the kernel could pass both to the server. */
356 cred
.pid
= __getpid ();
357 cred
.uid
= __geteuid ();
358 cred
.gid
= __getegid ();
360 memcpy (CMSG_DATA(cmsg
), &cred
, sizeof (struct ucred
));
361 cmsg
->cmsg_level
= SOL_SOCKET
;
362 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
363 cmsg
->cmsg_len
= sizeof(*cmsg
) + sizeof(struct ucred
);
372 msg
.msg_control
= cmsg
;
373 msg
.msg_controllen
= CMSG_ALIGN(cmsg
->cmsg_len
);
377 len
= sendmsg (sock
, &msg
, 0);
388 * reads data from the unix connection.
389 * any error is fatal and the connection is closed.
390 * (And a read of zero bytes is a half closed stream => error.)
393 readunix (char *xprtptr
, char *buf
, int len
)
395 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
396 int sock
= xprt
->xp_sock
;
397 int milliseconds
= 35 * 1000;
398 struct pollfd pollfd
;
403 pollfd
.events
= POLLIN
;
404 switch (__poll (&pollfd
, 1, milliseconds
))
413 if ((pollfd
.revents
& POLLERR
) || (pollfd
.revents
& POLLHUP
)
414 || (pollfd
.revents
& POLLNVAL
))
419 while ((pollfd
.revents
& POLLIN
) == 0);
421 if ((len
= __msgread (sock
, buf
, len
)) > 0)
425 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
430 * writes data to the unix connection.
431 * Any error is fatal and the connection is closed.
434 writeunix (char *xprtptr
, char * buf
, int len
)
436 SVCXPRT
*xprt
= (SVCXPRT
*) xprtptr
;
439 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
)
441 if ((i
= __msgwrite (xprt
->xp_sock
, buf
, cnt
)) < 0)
443 ((struct unix_conn
*) (xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
450 static enum xprt_stat
451 svcunix_stat (SVCXPRT
*xprt
)
453 struct unix_conn
*cd
=
454 (struct unix_conn
*) (xprt
->xp_p1
);
456 if (cd
->strm_stat
== XPRT_DIED
)
458 if (!xdrrec_eof (&(cd
->xdrs
)))
459 return XPRT_MOREREQS
;
464 svcunix_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
466 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
467 XDR
*xdrs
= &(cd
->xdrs
);
469 xdrs
->x_op
= XDR_DECODE
;
470 xdrrec_skiprecord (xdrs
);
471 if (xdr_callmsg (xdrs
, msg
))
473 cd
->x_id
= msg
->rm_xid
;
474 /* set up verifiers */
475 #ifdef SCM_CREDENTIALS
476 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
477 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
) &cm
;
478 msg
->rm_call
.cb_verf
.oa_length
= sizeof (cm
);
482 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
487 svcunix_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
489 return (*xdr_args
) (&(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
),
494 svcunix_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
496 XDR
*xdrs
= &(((struct unix_conn
*) (xprt
->xp_p1
))->xdrs
);
498 xdrs
->x_op
= XDR_FREE
;
499 return (*xdr_args
) (xdrs
, args_ptr
);
503 svcunix_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
505 struct unix_conn
*cd
= (struct unix_conn
*) (xprt
->xp_p1
);
506 XDR
*xdrs
= &(cd
->xdrs
);
509 xdrs
->x_op
= XDR_ENCODE
;
510 msg
->rm_xid
= cd
->x_id
;
511 stat
= xdr_replymsg (xdrs
, msg
);
512 (void) xdrrec_endofrecord (xdrs
, TRUE
);