glibc/sunrpc/svc_unix.c
Ulrich Drepper 7cabd57c0d Update.
1998-08-03 16:36  Ulrich Drepper  <drepper@cygnus.com>

	* catgets/catgets.c: Use mmap/munmap only is _POSIX_MAPPED_FILES
	is defined.
	* catgets/open_catalog.c: Likewise.
	* iconv/iconv_prog.c: Likewise.
	* intl/loadmsgcat.c: Likewise.
	* locale/findlocale.c: Likewise.
	* locale/loadlocale.c: Likewise.
	* locale/programs/localedef.c: Likewise.
	* malloc/malloc.c: Likewise.

	* elf/elf.h: Fix typo.

	* math/Makefile: Use $(LN_S) instead of ln.

	* sysdeps/generic/getpgid.c: Fix return type.

1998-08-01 02:49 -0400  Zack Weinberg  <zack@rabi.phys.columbia.edu>

	* sysdeps/posix/tempname.c (__stdio_gen_tempname): Rename to
	__gen_tempname and simplify the interface.  Strip out the
	code to do path search and create FILE objects.  This function
	now takes a mktemp() style template and returns either a name
	or a file descriptor.
	(__path_search): New function; searches for directories for
	temp files.
	* sysdeps/generic/tempname.c: Stub out __gen_tempname and
	__path_search, not __stdio_gen_tempname.

	* libio/stdio.h: Prototype __gen_tempname and __path_search,
	not __stdio_gen_tempname.
	* stdio/stdio.h: Likewise.

	* stdio-common/tempnam.c: Use __path_search and __gen_tempname.
	* stdio-common/tmpfile.c: Likewise.
	* stdio-common/tmpfile64.c: Likewise.
	* stdio-common/tmpnam.c: Likewise.
	* stdio-common/tmpnam_r.c: Likewise.

	* misc/mkstemp.c: New file.  Use __gen_tempname.
	* misc/mktemp.c: Likewise.

	* sysdeps/posix/mkstemp.c: Removed.
	* sysdeps/posix/mktemp.c: Removed.
	* sysdeps/generic/mkstemp.c: Removed.
	* sysdeps/generic/mktemp.c: Removed.

1998-08-02  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* configure.in: Check, if door add-on is installed.
	* config.make.in: Add have_doors.
	* sunrpc/Makefile: Add HAVE_DOOR define.
	* sunrpc/key_call.c: Add keyserv/door interface.

	* sunrpc/svc_unix.c: Call setsockopt only if SO_PASSCRED is defined.
	* sunrpc/clnt_unix.c: Likewise.

1998-08-02  Andreas Jaeger  <aj@arthur.rhein-neckar.de>

	* inet/netinet/in.h (IN_CLASSC): Correct mask.
	Reported by Ian Staniforth <I.Staniforth@sheffield.ac.uk> [fixes
	PR libc/727].

1998-08-03 10:23  Ulrich Drepper  <drepper@cygnus.com>

	* misc/Makefile: Fix installation problem with --disable-shared.
	* posix/Makefile: Likewise.

1998-08-02  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* posix/regex.c (re_search_2): Optimize searching for anchored
	pattern if '^' cannot match at embedded newlines.
	(regerror): Renamed from __regerror, which it should only be
	called if _LIBC.

1998-07-31  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sunrpc/svc_unix.c (__msgread): Check setsockopt return value.

1998-07-31  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/generic/glob.c: Remove obsolete cast.

1998-07-31  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Rules (tests): Fix last change.
1998-08-03 16:47:01 +00:00

500 lines
13 KiB
C

/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* svc_unix.c, Server side for TCP/IP based RPC.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* Actually implements two flavors of transporter -
* a unix rendezvouser (a listener and connection establisher)
* and a record/unix stream.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include <stdlib.h>
/*
* Ops vector for AF_UNIX based rpc service handle
*/
static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
static enum xprt_stat svcunix_stat (SVCXPRT *);
static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
static void svcunix_destroy (SVCXPRT *);
static const struct xp_ops svcunix_op =
{
svcunix_recv,
svcunix_stat,
svcunix_getargs,
svcunix_reply,
svcunix_freeargs,
svcunix_destroy
};
/*
* Ops vector for AF_UNIX rendezvous handler
*/
static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
static enum xprt_stat rendezvous_stat (SVCXPRT *);
static const struct xp_ops svcunix_rendezvous_op =
{
rendezvous_request,
rendezvous_stat,
(bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
(bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
(bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
svcunix_destroy
};
static int readunix (char*, char *, int);
static int writeunix (char *, char *, int);
static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
struct unix_rendezvous { /* kept in xprt->xp_p1 */
u_int sendsize;
u_int recvsize;
};
struct unix_conn { /* kept in xprt->xp_p1 */
enum xprt_stat strm_stat;
u_long x_id;
XDR xdrs;
char verf_body[MAX_AUTH_BYTES];
};
/*
* Usage:
* xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
*
* Creates, registers, and returns a (rpc) unix based transporter.
* Once *xprt is initialized, it is registered as a transporter
* see (svc.h, xprt_register). This routine returns
* a NULL if a problem occurred.
*
* If sock<0 then a socket is created, else sock is used.
* If the socket, sock is not bound to a port then svcunix_create
* binds it to an arbitrary port. The routine then starts a unix
* listener on the socket's associated port. In any (successful) case,
* xprt->xp_sock is the registered socket number and xprt->xp_port is the
* associated port number.
*
* Since unix streams do buffered io similar to stdio, the caller can specify
* how big the send and receive buffers are via the second and third parms;
* 0 => use the system default.
*/
SVCXPRT *
svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
{
bool_t madesock = FALSE;
SVCXPRT *xprt;
struct unix_rendezvous *r;
struct sockaddr_un addr;
socklen_t len = sizeof (struct sockaddr_in);
if (sock == RPC_ANYSOCK)
{
if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
perror (_("svc_unix.c - AF_UNIX socket creation problem"));
return (SVCXPRT *) NULL;
}
madesock = TRUE;
}
memset (&addr, '\0', sizeof (addr));
addr.sun_family = AF_UNIX;
len = strlen (path) + 1;
memcpy (addr.sun_path, path, len);
len += sizeof (addr.sun_family);
bind (sock, (struct sockaddr *) &addr, len);
if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
|| listen (sock, 2) != 0)
{
perror (_("svc_unix.c - cannot getsockname or listen"));
if (madesock)
__close (sock);
return (SVCXPRT *) NULL;
}
r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
if (r == NULL)
{
fputs (_("svcunix_create: out of memory\n"), stderr);
return NULL;
}
r->sendsize = sendsize;
r->recvsize = recvsize;
xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
if (xprt == NULL)
{
fputs (_("svcunix_create: out of memory\n"), stderr);
return NULL;
}
xprt->xp_p2 = NULL;
xprt->xp_p1 = (caddr_t) r;
xprt->xp_verf = _null_auth;
xprt->xp_ops = &svcunix_rendezvous_op;
xprt->xp_port = -1;
xprt->xp_sock = sock;
xprt_register (xprt);
return xprt;
}
/*
* Like svunix_create(), except the routine takes any *open* UNIX file
* descriptor as its first input.
*/
SVCXPRT *
svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
{
return makefd_xprt (fd, sendsize, recvsize);
}
static SVCXPRT *
internal_function
makefd_xprt (int fd, u_int sendsize, u_int recvsize)
{
SVCXPRT *xprt;
struct unix_conn *cd;
xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
if (xprt == (SVCXPRT *) NULL)
{
(void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
goto done;
}
cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
if (cd == (struct unix_conn *) NULL)
{
(void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
mem_free ((char *) xprt, sizeof (SVCXPRT));
xprt = (SVCXPRT *) NULL;
goto done;
}
cd->strm_stat = XPRT_IDLE;
xdrrec_create (&(cd->xdrs), sendsize, recvsize,
(caddr_t) xprt, readunix, writeunix);
xprt->xp_p2 = NULL;
xprt->xp_p1 = (caddr_t) cd;
xprt->xp_verf.oa_base = cd->verf_body;
xprt->xp_addrlen = 0;
xprt->xp_ops = &svcunix_op; /* truly deals with calls */
xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
xprt->xp_sock = fd;
xprt_register (xprt);
done:
return xprt;
}
static bool_t
rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
{
int sock;
struct unix_rendezvous *r;
struct sockaddr_un addr;
struct sockaddr_in in_addr;
socklen_t len;
r = (struct unix_rendezvous *) xprt->xp_p1;
again:
len = sizeof (struct sockaddr_un);
if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
{
if (errno == EINTR)
goto again;
return FALSE;
}
/*
* make a new transporter (re-uses xprt)
*/
memset (&in_addr, '\0', sizeof (in_addr));
in_addr.sin_family = AF_UNIX;
xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
xprt->xp_raddr = in_addr;
xprt->xp_addrlen = len;
return FALSE; /* there is never an rpc msg to be processed */
}
static enum xprt_stat
rendezvous_stat (SVCXPRT *xprt)
{
return XPRT_IDLE;
}
static void
svcunix_destroy (SVCXPRT *xprt)
{
struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
xprt_unregister (xprt);
__close (xprt->xp_sock);
if (xprt->xp_port != 0)
{
/* a rendezvouser socket */
xprt->xp_port = 0;
}
else
{
/* an actual connection socket */
XDR_DESTROY (&(cd->xdrs));
}
mem_free ((caddr_t) cd, sizeof (struct unix_conn));
mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
}
struct cmessage {
struct cmsghdr cmsg;
struct cmsgcred cmcred;
};
/* XXX This is not thread safe, but since the main functions in svc.c
and the rpcgen generated *_svc functions for the daemon are also not
thread safe and uses static global variables, it doesn't matter. */
static struct cmessage cm;
static int
__msgread (int sock, void *buf, size_t cnt)
{
struct iovec iov[1];
struct msghdr msg;
int on = 1;
iov[0].iov_base = buf;
iov[0].iov_len = cnt;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t) &cm;
msg.msg_controllen = sizeof (struct cmessage);
msg.msg_flags = 0;
#ifdef SO_PASSCRED
if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
return -1;
#endif
return recvmsg (sock, &msg, 0);
}
static int
__msgwrite (int sock, void *buf, size_t cnt)
{
#ifndef SCM_CREDS
/* We cannot implement this reliably. */
__set_errno (ENOSYS);
return -1;
#else
struct iovec iov[1];
struct msghdr msg;
iov[0].iov_base = buf;
iov[0].iov_len = cnt;
cm.cmsg.cmsg_type = SCM_CREDS;
cm.cmsg.cmsg_level = SOL_SOCKET;
cm.cmsg.cmsg_len = sizeof (struct cmessage);
/* XXX I'm not sure, if we really should use gete?id(), or get?id().
It would be much better, if the kernel could pass both to the
client. */
cm.cmcred.cmcred_pid = __getpid ();
cm.cmcred.cmcred_uid = __geteuid ();
cm.cmcred.cmcred_gid = __getegid ();
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t) &cm;
msg.msg_controllen = sizeof (struct cmessage);
msg.msg_flags = 0;
return sendmsg (sock, &msg, 0);
#endif
}
/*
* All read operations timeout after 35 seconds.
* A timeout is fatal for the connection.
*/
static struct timeval wait_per_try = {35, 0};
/*
* reads data from the unix connection.
* any error is fatal and the connection is closed.
* (And a read of zero bytes is a half closed stream => error.)
*/
static int
readunix (char *xprtptr, char *buf, int len)
{
SVCXPRT *xprt = (SVCXPRT *) xprtptr;
int sock = xprt->xp_sock;
#ifdef FD_SETSIZE
fd_set readfds;
#else
int mask = 1 << sock;
int readfds;
#endif /* def FD_SETSIZE */
while (1)
{
struct timeval timeout = wait_per_try;
readfds = svc_fdset;
#ifdef FD_SETSIZE
FD_SET (sock, &readfds);
#else
readfds |= (1 << sock);
#endif /* def FD_SETSIZE */
if (__select (_rpc_dtablesize (), &readfds, (fd_set *) NULL,
(fd_set *) NULL, &timeout) <= 0)
{
if (errno == EINTR)
continue;
goto fatal_err;
}
#ifdef FD_SETSIZE
if (FD_ISSET (sock, &readfds))
#else
if (readfds == mask)
#endif /* def FD_SETSIZE */
break;
svc_getreqset (&readfds);
}
if ((len = __msgread (sock, buf, len)) > 0)
return len;
fatal_err:
((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
return -1;
}
/*
* writes data to the unix connection.
* Any error is fatal and the connection is closed.
*/
static int
writeunix (char *xprtptr, char * buf, int len)
{
SVCXPRT *xprt = (SVCXPRT *) xprtptr;
int i, cnt;
for (cnt = len; cnt > 0; cnt -= i, buf += i)
{
if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
{
((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
return -1;
}
}
return len;
}
static enum xprt_stat
svcunix_stat (SVCXPRT *xprt)
{
struct unix_conn *cd =
(struct unix_conn *) (xprt->xp_p1);
if (cd->strm_stat == XPRT_DIED)
return XPRT_DIED;
if (!xdrrec_eof (&(cd->xdrs)))
return XPRT_MOREREQS;
return XPRT_IDLE;
}
static bool_t
svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
{
struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
XDR *xdrs = &(cd->xdrs);
xdrs->x_op = XDR_DECODE;
xdrrec_skiprecord (xdrs);
if (xdr_callmsg (xdrs, msg))
{
cd->x_id = msg->rm_xid;
/* set up verifiers */
msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
msg->rm_call.cb_verf.oa_length = sizeof (cm);
return TRUE;
}
cd->strm_stat = XPRT_DIED; /* XXXX */
return FALSE;
}
static bool_t
svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
{
return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
args_ptr);
}
static bool_t
svcunix_freeargs (xprt, xdr_args, args_ptr)
SVCXPRT *xprt;
xdrproc_t xdr_args;
caddr_t args_ptr;
{
XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
xdrs->x_op = XDR_FREE;
return (*xdr_args) (xdrs, args_ptr);
}
static bool_t
svcunix_reply (xprt, msg)
SVCXPRT *xprt;
struct rpc_msg *msg;
{
struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
XDR *xdrs = &(cd->xdrs);
bool_t stat;
xdrs->x_op = XDR_ENCODE;
msg->rm_xid = cd->x_id;
stat = xdr_replymsg (xdrs, msg);
(void) xdrrec_endofrecord (xdrs, TRUE);
return stat;
}