summaryrefslogtreecommitdiff
path: root/sunrpc
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1998-07-28 16:26:04 +0000
committerUlrich Drepper <drepper@redhat.com>1998-07-28 16:26:04 +0000
commite852e889444a8bf27f3e5075d064e9922b38e7e2 (patch)
tree75d2d4b1010a26d723daefef7909d1a6355929bc /sunrpc
parentc9243dacea19b7dcf36bb69ca83877d3ea905831 (diff)
Update.
1998-07-28 Ulrich Drepper <drepper@cygnus.com> * math/libm-test.c (tgamma_test): Remove redundant tests. 1998-07-28 16:20 Ulrich Drepper <drepper@cygnus.com> * sysdeps/generic/glob.c: Correct problems with */foo and GLOB_NOCHECK where foo does not exist in any of the subdirectories. Reported by Paul D. Smith <psmith@BayNetworks.COM>. * posix/globtest.sh: Add test for this bug. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * io/sys/statfs.h: Fix typos. * io/sys/statvfs.h: Fix typos. 1998-07-28 Ulrich Drepper <drepper@cygnus.com> * version.h (VERSION): Bump to 2.0.95. * math/Makefile (libm-calls): Remove w_gamma, add w_tgamma. * math/Versions [GLIBC_2.1]: Add tgamma, tgammaf, and tgammal. * math/libm-test.c: Split old gamma_test and move half of it in new function tgamma_test. * math/bits/mathcalls.h: Add declaration of tgamma. * sysdeps/libm-ieee754/k_standard.c: Change gamma errors into tgamma errors. * sysdeps/libm-ieee754/w_gamma.c: Remove lgamma compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgamma.c: ... this. New file. * sysdeps/libm-ieee754/w_gammaf.c: Remove lgammaf compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgammaf.c: ... this. New file. * sysdeps/libm-ieee754/w_gammal.c: Remove lgammal compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgammal.c: ... this. New file. * sysdeps/libm-ieee754/w_lgamma.c: Add gamma as weak alias. * sysdeps/libm-ieee754/w_lgammaf.c: Likewise. * sysdeps/libm-ieee754/w_lgammal.c: Likewise. * stgdio-common/printf-parse.h: Implement handling of j, t, and z modifiers. * stdio-common/vfprintf.c: Likewise. * stdio-common/vfscanf.c: Likewise. * manual/stdio.texi: Document new printf/scanf modifiers. * sysdeps/unix/sysv/linux/recvmsg.c: Remove alias __recvmsg. * sysdeps/unix/sysv/linux/sendmsg.c: Remove alias __sendmsg. 1998-07-28 Thorsten Kukuk <kukuk@vt.uni-paderborn.de> * sunrpc/Makefile (routines): Add clnt_unix and svc_unix. * sunrpc/Versions: Add new *unix_create functions. * sunrpc/clnt_gen.c: Add support for RPC over AF_UNIX. * sunrpc/clnt_unix.c: New, client side of RPC over AF_UNIX. * sunrpc/key_call.c: Use RPC over AF_UNIX for communication with keyserv daemon. * sunrpc/rpc/clnt.h: Add AF_UNIX based RPC function prototypes. * sunrpc/rpc/svc.h: Likewise. * sunrpc/svc_authux.c: Copy internal auth flavor if none is given. * sunrpc/svc_tcp.c: Fix typos. * sunrpc/svc_unix.c: New, server side of AF_UNIX based RPC. * nis/Makefile: Remove currently not working cache functions. * nis/Versions: Add __nisbind_* functions for rpc.nisd. * nis/nis_call.c: Rewrite binding to a NIS+ server to reuse CLIENT handles. * nis/nis_file.c: Fix memory leaks. * nis/nis_intern.h: Move internal structs from here ... * nis/rpcsvc/nislib.h: ... to here for NIS+ server and tools. * nis/nis_lookup.c: Try at first if last client handle works. * nis/nis_table.c: Likewise. * nis/nis_checkpoint.c: Adjust __do_niscall2 parameters. * nis/nis_mkdir.c: Likewise. * nis/nis_ping.c: Likewise. * nis/nis_rmdir.c: Likewise. * nis/nis_server.c: Likewise. * nis/nis_util.c: Likewise. * nis/nis_findserv.c (__nis_findfastest): Little optimization. 1998-07-28 Andreas Jaeger <aj@arthur.rhein-neckar.de> * stdlib/strtol.c (STRTOL_LONG_MAX): Correct typo in last patch - define as LONG_MAX. 1998-07-28 09:31 Ulrich Drepper <drepper@cygnus.com> * nscd/connections.c (gr_send_answer): Deal with missing UIO_MAXIOV. Correct test whether writev send all data. * nscd/nscd_getgr_r.c (__nscd_getgr_r): Correct test whether readv received all data. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * nscd/nscd_getgr_r.c (__nscd_getgr_r): Deal with missing UIO_MAXIOV. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * sysdeps/mach/hurd/dl-sysdep.c (open_file): Change assert call to allow mode to be 0. (__xstat): New function. (__fxstat): New function. (_dl_sysdep_read_whole_file): Removed. The implementation in `elf/dl-misc.c' now also works for the Hurd.
Diffstat (limited to 'sunrpc')
-rw-r--r--sunrpc/Makefile3
-rw-r--r--sunrpc/Versions5
-rw-r--r--sunrpc/clnt_gen.c16
-rw-r--r--sunrpc/clnt_unix.c573
-rw-r--r--sunrpc/key_call.c200
-rw-r--r--sunrpc/rpc/clnt.h22
-rw-r--r--sunrpc/rpc/svc.h7
-rw-r--r--sunrpc/svc_authux.c18
-rw-r--r--sunrpc/svc_tcp.c4
-rw-r--r--sunrpc/svc_unix.c496
10 files changed, 1313 insertions, 31 deletions
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 2ab2577f08..2dac9937f3 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -66,7 +66,8 @@ routines := auth_none auth_unix authuxprot bindrsvprt \
svc_tcp svc_udp xdr xdr_array xdr_float xdr_mem \
xdr_rec xdr_ref xdr_stdio publickey xdr_sizeof \
auth_des authdes_prot des_crypt des_impl des_soft \
- key_call key_prot netname openchild rtime svcauth_des xcrypt
+ key_call key_prot netname openchild rtime svcauth_des xcrypt\
+ clnt_unix svc_unix
others := rpcinfo
install-bin := rpcgen
diff --git a/sunrpc/Versions b/sunrpc/Versions
index d956486f9f..98dfbbc79f 100644
--- a/sunrpc/Versions
+++ b/sunrpc/Versions
@@ -59,7 +59,7 @@ libc {
authdes_create; authdes_getucred; authdes_pk_create;
# c*
- cbc_crypt;
+ cbc_crypt; clntunix_create;
# d*
des_setparity;
@@ -87,6 +87,9 @@ libc {
# r*
rtime;
+ # s*
+ svcunix_create; svcunixfd_create;
+
# u*
user2netname;
diff --git a/sunrpc/clnt_gen.c b/sunrpc/clnt_gen.c
index b1b35ca50a..f62618bdac 100644
--- a/sunrpc/clnt_gen.c
+++ b/sunrpc/clnt_gen.c
@@ -57,11 +57,27 @@ clnt_create (const char *hostname, u_long prog, u_long vers,
size_t prtbuflen;
char *prttmpbuf;
struct sockaddr_in sin;
+ struct sockaddr_un sun;
int sock;
struct timeval tv;
CLIENT *client;
int herr;
+ if (strcmp (proto, "unix") == 0)
+ {
+ __bzero ((char *)&sun, sizeof (sun));
+ sun.sun_family = AF_UNIX;
+ strcpy (sun.sun_path, hostname);
+ sock = RPC_ANYSOCK;
+ client = clntunix_create (&sun, prog, vers, &sock, 0, 0);
+ if (client == NULL)
+ return NULL;
+ tv.tv_sec = 25;
+ tv.tv_usec = 0;
+ clnt_control (client, CLSET_TIMEOUT, (char *)&tv);
+ return client;
+ }
+
hstbuflen = 1024;
hsttmpbuf = __alloca (hstbuflen);
while (__gethostbyname_r (hostname, &hostbuf, hsttmpbuf, hstbuflen,
diff --git a/sunrpc/clnt_unix.c b/sunrpc/clnt_unix.c
new file mode 100644
index 0000000000..848b752e6b
--- /dev/null
+++ b/sunrpc/clnt_unix.c
@@ -0,0 +1,573 @@
+/*
+ * 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
+ */
+
+/*
+ * clnt_unix.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer. The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent. The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message. Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <rpc/pmap_clnt.h>
+
+#define MCALL_MSG_SIZE 24
+
+struct ct_data
+ {
+ int ct_sock;
+ bool_t ct_closeit;
+ struct timeval ct_wait;
+ bool_t ct_waitset; /* wait set by clnt_control? */
+ struct sockaddr_un ct_addr;
+ struct rpc_err ct_error;
+ char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
+ u_int ct_mpos; /* pos after marshal */
+ XDR ct_xdrs;
+ };
+
+static int readunix (char *, char *, int);
+static int writeunix (char *, char *, int);
+
+static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
+ xdrproc_t, caddr_t, struct timeval);
+static void clntunix_abort (void);
+static void clntunix_geterr (CLIENT *, struct rpc_err *);
+static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
+static bool_t clntunix_control (CLIENT *, int, char *);
+static void clntunix_destroy (CLIENT *);
+
+static struct clnt_ops unix_ops =
+{
+ clntunix_call,
+ clntunix_abort,
+ clntunix_geterr,
+ clntunix_freeres,
+ clntunix_destroy,
+ clntunix_control
+};
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr. If *sockp non-negative then
+ * raddr is ignored. The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
+ int *sockp, u_int sendsz, u_int recvsz)
+{
+ CLIENT *h;
+ struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
+ struct timeval now;
+ struct rpc_msg call_msg;
+ int len;
+
+ h = (CLIENT *) mem_alloc (sizeof (*h));
+ if (h == NULL)
+ {
+ (void) fputs (_("clntunix_create: out of memory\n"), stderr);
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ goto fooy;
+ }
+ /* ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
+ if (ct == NULL)
+ {
+ (void) fputs (_("clntunix_create: out of memory\n"), stderr);
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ goto fooy;
+ }
+
+ /*
+ * If no socket given, open one
+ */
+ if (*sockp < 0)
+ {
+ *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
+ len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
+ if (*sockp < 0
+ || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
+ {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ if (*sockp != -1)
+ __close (*sockp);
+ goto fooy;
+ }
+ ct->ct_closeit = TRUE;
+ }
+ else
+ {
+ ct->ct_closeit = FALSE;
+ }
+
+ /*
+ * Set up private data struct
+ */
+ ct->ct_sock = *sockp;
+ ct->ct_wait.tv_usec = 0;
+ ct->ct_waitset = FALSE;
+ ct->ct_addr = *raddr;
+
+ /*
+ * Initialize call message
+ */
+ __gettimeofday (&now, (struct timezone *) 0);
+ call_msg.rm_xid = __getpid () ^ now.tv_sec ^ now.tv_usec;
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = prog;
+ call_msg.rm_call.cb_vers = vers;
+
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
+ if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
+ {
+ if (ct->ct_closeit)
+ __close (*sockp);
+ goto fooy;
+ }
+ ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
+ XDR_DESTROY (&(ct->ct_xdrs));
+
+ /*
+ * Create a client handle which uses xdrrec for serialization
+ * and authnone for authentication.
+ */
+ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
+ (caddr_t) ct, readunix, writeunix);
+ h->cl_ops = &unix_ops;
+ h->cl_private = (caddr_t) ct;
+ h->cl_auth = authnone_create ();
+ return h;
+
+fooy:
+ /*
+ * Something goofed, free stuff and barf
+ */
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+ return (CLIENT *) NULL;
+}
+
+static enum clnt_stat
+clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
+ CLIENT *h;
+ u_long proc;
+ xdrproc_t xdr_args;
+ caddr_t args_ptr;
+ xdrproc_t xdr_results;
+ caddr_t results_ptr;
+ struct timeval timeout;
+{
+ struct ct_data *ct = (struct ct_data *) h->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+ struct rpc_msg reply_msg;
+ u_long x_id;
+ u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
+ bool_t shipnow;
+ int refreshes = 2;
+
+ if (!ct->ct_waitset)
+ {
+ ct->ct_wait = timeout;
+ }
+
+ shipnow =
+ (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
+ && timeout.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+ xdrs->x_op = XDR_ENCODE;
+ ct->ct_error.re_status = RPC_SUCCESS;
+ x_id = ntohl (--(*msg_x_id));
+ if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
+ (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
+ (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
+ (!(*xdr_args) (xdrs, args_ptr)))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTENCODEARGS;
+ (void) xdrrec_endofrecord (xdrs, TRUE);
+ return ct->ct_error.re_status;
+ }
+ if (!xdrrec_endofrecord (xdrs, shipnow))
+ return ct->ct_error.re_status = RPC_CANTSEND;
+ if (!shipnow)
+ return RPC_SUCCESS;
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
+ return ct->ct_error.re_status = RPC_TIMEDOUT;
+
+
+ /*
+ * Keep receiving until we get a valid transaction id
+ */
+ xdrs->x_op = XDR_DECODE;
+ while (TRUE)
+ {
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ if (!xdrrec_skiprecord (xdrs))
+ return ct->ct_error.re_status;
+ /* now decode and validate the response header */
+ if (!xdr_replymsg (xdrs, &reply_msg))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ continue;
+ return ct->ct_error.re_status;
+ }
+ if (reply_msg.rm_xid == x_id)
+ break;
+ }
+
+ /*
+ * process header
+ */
+ _seterr_reply (&reply_msg, &(ct->ct_error));
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
+ {
+ ct->ct_error.re_status = RPC_AUTHERROR;
+ ct->ct_error.re_why = AUTH_INVALIDRESP;
+ }
+ else if (!(*xdr_results) (xdrs, results_ptr))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTDECODERES;
+ }
+ /* free verifier ... */
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
+ {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ else
+ {
+ /* maybe our credentials need to be refreshed ... */
+ if (refreshes-- && AUTH_REFRESH (h->cl_auth))
+ goto call_again;
+ } /* end of unsuccessful completion */
+ return ct->ct_error.re_status;
+}
+
+static void
+clntunix_geterr (CLIENT *h, struct rpc_err *errp)
+{
+ struct ct_data *ct = (struct ct_data *) h->cl_private;
+
+ *errp = ct->ct_error;
+}
+
+static bool_t
+clntunix_freeres (cl, xdr_res, res_ptr)
+ CLIENT *cl;
+ xdrproc_t xdr_res;
+ caddr_t res_ptr;
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_res) (xdrs, res_ptr);
+}
+
+static void
+clntunix_abort ()
+{
+}
+
+static bool_t
+clntunix_control (CLIENT *cl, int request, char *info)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+
+ switch (request)
+ {
+ case CLSET_FD_CLOSE:
+ ct->ct_closeit = TRUE;
+ break;
+ case CLSET_FD_NCLOSE:
+ ct->ct_closeit = FALSE;
+ break;
+ case CLSET_TIMEOUT:
+ ct->ct_wait = *(struct timeval *) info;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *) info = ct->ct_wait;
+ break;
+ case CLGET_SERVER_ADDR:
+ *(struct sockaddr_un *) info = ct->ct_addr;
+ break;
+ case CLGET_FD:
+ *(int *)info = ct->ct_sock;
+ break;
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure *.
+ * This will get the xid of the PREVIOUS call
+ */
+ *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
+ /* decrement by 1 as clntunix_call() increments once */
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
+ + 4 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_VERS:
+ *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
+ = htonl (*(u_long *) info);
+ break;
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
+ + 3 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_PROG:
+ *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_long *) info);
+ break;
+ /* The following are only possible with TI-RPC */
+ case CLGET_RETRY_TIMEOUT:
+ case CLSET_RETRY_TIMEOUT:
+ case CLGET_SVC_ADDR:
+ case CLSET_SVC_ADDR:
+ case CLSET_PUSH_TIMOD:
+ case CLSET_POP_TIMOD:
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void
+clntunix_destroy (CLIENT *h)
+{
+ struct ct_data *ct =
+ (struct ct_data *) h->cl_private;
+
+ if (ct->ct_closeit)
+ {
+ (void) close (ct->ct_sock);
+ }
+ XDR_DESTROY (&(ct->ct_xdrs));
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+}
+
+struct cmessage {
+ struct cmsghdr cmsg;
+ struct cmsgcred cmcred;
+};
+
+static int
+__msgread (int sock, void *buf, size_t cnt)
+{
+ struct iovec iov[1];
+ struct msghdr msg;
+ struct cmessage cm;
+ 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;
+
+ setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
+
+ return recvmsg (sock, &msg, 0);
+}
+
+static int
+__msgwrite (int sock, void *buf, size_t cnt)
+{
+#ifndef SCM_CRED
+ /* We cannot implement this reliably. */
+ __set_errno (ENOSYS);
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+ struct cmessage cm;
+ int len;
+
+ 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 gete?id() is always correct, or if we should use
+ get?id(). But since keyserv needs geteuid(), we have no other chance.
+ It would be much better, if the kernel could pass both to the server. */
+ 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
+}
+
+
+/*
+ * Interface between xdr serializer and unix connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readunix (char *ctptr, char *buf, int len)
+{
+ struct ct_data *ct = (struct ct_data *) ctptr;
+ struct pollfd fd;
+ int milliseconds = ((ct->ct_wait.tv_sec * 1000)
+ + (ct->ct_wait.tv_usec / 1000));
+
+ if (len == 0)
+ return 0;
+
+ fd.fd = ct->ct_sock;
+ fd.events = POLLIN;
+ while (TRUE)
+ {
+ switch (__poll (&fd, 1, milliseconds))
+ {
+ case 0:
+ ct->ct_error.re_status = RPC_TIMEDOUT;
+ return -1;
+
+ case -1:
+ if (errno == EINTR)
+ continue;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ ct->ct_error.re_errno = errno;
+ return -1;
+ }
+ break;
+ }
+ switch (len = __msgread (ct->ct_sock, buf, len))
+ {
+
+ case 0:
+ /* premature eof */
+ ct->ct_error.re_errno = ECONNRESET;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ len = -1; /* it's really an error */
+ break;
+
+ case -1:
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ break;
+ }
+ return len;
+}
+
+static int
+writeunix (char *ctptr, char *buf, int len)
+{
+ int i, cnt;
+ struct ct_data *ct = (struct ct_data *) ctptr;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i)
+ {
+ if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
+ {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return -1;
+ }
+ }
+ return len;
+}
diff --git a/sunrpc/key_call.c b/sunrpc/key_call.c
index e59a8b7a37..0219eaf5ad 100644
--- a/sunrpc/key_call.c
+++ b/sunrpc/key_call.c
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
@@ -47,6 +48,7 @@
#include <sys/param.h>
#include <sys/socket.h>
#include <rpc/key_prot.h>
+#include <bits/libc-lock.h>
#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
#define KEY_NRETRY 12 /* number of retries */
@@ -268,8 +270,8 @@ des_block *(*__key_gendes_LOCAL) (uid_t, char *) = 0;
static int
internal_function
-key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
- xdrproc_t xdr_rslt, char *rslt)
+key_call_keyenvoy (u_long proc, xdrproc_t xdr_arg, char *arg,
+ xdrproc_t xdr_rslt, char *rslt)
{
XDR xdrargs;
XDR xdrrslt;
@@ -283,28 +285,6 @@ key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
uid_t euid;
static char MESSENGER[] = "/usr/etc/keyenvoy";
- if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
- {
- cryptkeyres *res;
- res = (*__key_encryptsession_pk_LOCAL) (__geteuid (), arg);
- *(cryptkeyres *) rslt = *res;
- return 1;
- }
- else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
- {
- cryptkeyres *res;
- res = (*__key_decryptsession_pk_LOCAL) (__geteuid (), arg);
- *(cryptkeyres *) rslt = *res;
- return 1;
- }
- else if (proc == KEY_GEN && __key_gendes_LOCAL)
- {
- des_block *res;
- res = (*__key_gendes_LOCAL) (__geteuid (), 0);
- *(des_block *) rslt = *res;
- return 1;
- }
-
success = 1;
sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);
@@ -365,3 +345,175 @@ key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
return success;
}
+
+struct key_call_private {
+ CLIENT *client; /* Client handle */
+ pid_t pid; /* process-id at moment of creation */
+ uid_t uid; /* user-id at last authorization */
+};
+static struct key_call_private *key_call_private_main = NULL;
+__libc_lock_define_initialized (static, keycall_lock)
+
+/*
+ * Keep the handle cached. This call may be made quite often.
+ */
+static CLIENT *
+getkeyserv_handle (int vers)
+{
+ struct key_call_private *kcp = key_call_private_main;
+ struct timeval wait_time;
+ int fd;
+ struct sockaddr_un name;
+ int namelen = sizeof(struct sockaddr_un);
+
+#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
+#define TOTAL_TRIES 5 /* Number of tries */
+
+ if (kcp == (struct key_call_private *)NULL)
+ {
+ kcp = (struct key_call_private *)malloc (sizeof (*kcp));
+ if (kcp == (struct key_call_private *)NULL)
+ return (CLIENT *) NULL;
+
+ key_call_private_main = kcp;
+ kcp->client = NULL;
+ }
+
+ /* if pid has changed, destroy client and rebuild */
+ if (kcp->client != NULL && kcp->pid != __getpid ())
+ {
+ clnt_destroy (kcp->client);
+ kcp->client = NULL;
+ }
+
+ if (kcp->client != NULL)
+ {
+ /* if other side closed socket, build handle again */
+ clnt_control (kcp->client, CLGET_FD, (char *)&fd);
+ if (getpeername (fd,(struct sockaddr *)&name,&namelen) == -1)
+ {
+ auth_destroy (kcp->client->cl_auth);
+ clnt_destroy (kcp->client);
+ kcp->client = NULL;
+ }
+ }
+
+ if (kcp->client != NULL)
+ {
+ /* if uid has changed, build client handle again */
+ if (kcp->uid != __geteuid ())
+ {
+ kcp->uid = __geteuid ();
+ auth_destroy (kcp->client->cl_auth);
+ kcp->client->cl_auth =
+ authunix_create ((char *)"", kcp->uid, 0, 0, NULL);
+ if (kcp->client->cl_auth == NULL)
+ {
+ clnt_destroy (kcp->client);
+ kcp->client = NULL;
+ return ((CLIENT *) NULL);
+ }
+ }
+ /* Change the version number to the new one */
+ clnt_control (kcp->client, CLSET_VERS, (void *)&vers);
+ return kcp->client;
+ }
+
+ if ((kcp->client == (CLIENT *) NULL))
+ /* Use the AF_UNIX transport */
+ kcp->client = clnt_create ("/var/run/keyservsock", KEY_PROG, vers, "unix");
+
+ if (kcp->client == (CLIENT *) NULL)
+ return (CLIENT *) NULL;
+
+ kcp->uid = __geteuid ();
+ kcp->pid = __getpid ();
+ kcp->client->cl_auth = authunix_create ((char *)"", kcp->uid, 0, 0, NULL);
+ if (kcp->client->cl_auth == NULL)
+ {
+ clnt_destroy (kcp->client);
+ kcp->client = NULL;
+ return (CLIENT *) NULL;
+ }
+
+ wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
+ wait_time.tv_usec = 0;
+ clnt_control (kcp->client, CLSET_RETRY_TIMEOUT,
+ (char *)&wait_time);
+ if (clnt_control (kcp->client, CLGET_FD, (char *)&fd))
+ fcntl (fd, F_SETFD, 1); /* make it "close on exec" */
+
+ return kcp->client;
+}
+
+/* returns 0 on failure, 1 on success */
+static int
+internal_function
+key_call_socket (u_long proc, xdrproc_t xdr_arg, char *arg,
+ xdrproc_t xdr_rslt, char *rslt)
+{
+ CLIENT *clnt;
+ struct timeval wait_time;
+ int result = 0;
+
+ __libc_lock_lock (keycall_lock);
+ if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
+ (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
+ (proc == KEY_GET_CONV))
+ clnt = getkeyserv_handle(2); /* talk to version 2 */
+ else
+ clnt = getkeyserv_handle(1); /* talk to version 1 */
+
+ if (clnt != NULL)
+ {
+ wait_time.tv_sec = TOTAL_TIMEOUT;
+ wait_time.tv_usec = 0;
+
+ if (clnt_call (clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
+ wait_time) == RPC_SUCCESS)
+ result = 1;
+ }
+
+ __libc_lock_unlock (keycall_lock);
+
+ return result;
+}
+
+/* returns 0 on failure, 1 on success */
+static int
+internal_function
+key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
+ xdrproc_t xdr_rslt, char *rslt)
+{
+ static int use_keyenvoy = 0;
+
+ if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
+ {
+ cryptkeyres *res;
+ res = (*__key_encryptsession_pk_LOCAL) (__geteuid (), arg);
+ *(cryptkeyres *) rslt = *res;
+ return 1;
+ }
+ else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
+ {
+ cryptkeyres *res;
+ res = (*__key_decryptsession_pk_LOCAL) (__geteuid (), arg);
+ *(cryptkeyres *) rslt = *res;
+ return 1;
+ }
+ else if (proc == KEY_GEN && __key_gendes_LOCAL)
+ {
+ des_block *res;
+ res = (*__key_gendes_LOCAL) (__geteuid (), 0);
+ *(des_block *) rslt = *res;
+ return 1;
+ }
+
+ if (!use_keyenvoy)
+ {
+ if (key_call_socket (proc, xdr_arg, arg, xdr_rslt, rslt))
+ return 1;
+ use_keyenvoy = 1;
+ }
+ return key_call_keyenvoy (proc, xdr_arg, arg, xdr_rslt, rslt);
+}
diff --git a/sunrpc/rpc/clnt.h b/sunrpc/rpc/clnt.h
index 1570cba4c2..b3852927a3 100644
--- a/sunrpc/rpc/clnt.h
+++ b/sunrpc/rpc/clnt.h
@@ -41,6 +41,7 @@
#include <sys/types.h>
#include <rpc/types.h>
#include <rpc/auth.h>
+#include <sys/un.h>
__BEGIN_DECLS
@@ -282,7 +283,8 @@ extern CLIENT *clntraw_create __P ((__const u_long __prog,
/*
- * Generic client creation routine. Supported protocols are "udp" and "tcp"
+ * Generic client creation routine. Supported protocols are "udp", "tcp" and
+ * "unix"
* CLIENT *
* clnt_create(host, prog, vers, prot)
* char *host; -- hostname
@@ -341,6 +343,24 @@ extern CLIENT *clntudp_bufcreate __P ((struct sockaddr_in *__raddr,
int *__sockp, u_int __sendsz,
u_int __recvsz));
+
+/*
+ * AF_UNIX based rpc
+ * CLIENT *
+ * clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ * struct sockaddr_un *raddr;
+ * u_long prog;
+ * u_long version;
+ * register int *sockp;
+ * u_int sendsz;
+ * u_int recvsz;
+ */
+extern CLIENT *clntunix_create __P ((struct sockaddr_un *__raddr,
+ u_long __program, u_long __version,
+ int *__sockp, u_int __sendsz,
+ u_int __recvsz));
+
+
extern int callrpc __P ((__const char *__host, __const u_long __prognum,
__const u_long __versnum, __const u_long __procnum,
__const xdrproc_t __inproc, __const char *__in,
diff --git a/sunrpc/rpc/svc.h b/sunrpc/rpc/svc.h
index a53bc1015f..4ac2a5cdf0 100644
--- a/sunrpc/rpc/svc.h
+++ b/sunrpc/rpc/svc.h
@@ -305,6 +305,13 @@ extern SVCXPRT *svctcp_create __P ((int __sock, u_int __sendsize,
u_int __recvsize));
+/*
+ * Unix based rpc.
+ */
+extern SVCXPRT *svcunix_create __P ((int __sock, u_int __sendsize,
+ u_int __recvsize, char *__path));
+
+
__END_DECLS
#endif /* rpc/svc.h */
diff --git a/sunrpc/svc_authux.c b/sunrpc/svc_authux.c
index 04cff9c53a..627b7e3faf 100644
--- a/sunrpc/svc_authux.c
+++ b/sunrpc/svc_authux.c
@@ -120,8 +120,22 @@ _svcauth_unix (struct svc_req *rqst, struct rpc_msg *msg)
stat = AUTH_BADCRED;
goto done;
}
- rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
- rqst->rq_xprt->xp_verf.oa_length = 0;
+
+ /* get the verifier */
+ if ((u_int)msg->rm_call.cb_verf.oa_length)
+ {
+ rqst->rq_xprt->xp_verf.oa_flavor =
+ msg->rm_call.cb_verf.oa_flavor;
+ rqst->rq_xprt->xp_verf.oa_base =
+ msg->rm_call.cb_verf.oa_base;
+ rqst->rq_xprt->xp_verf.oa_length =
+ msg->rm_call.cb_verf.oa_length;
+ }
+ else
+ {
+ rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
+ rqst->rq_xprt->xp_verf.oa_length = 0;
+ }
stat = AUTH_OK;
done:
XDR_DESTROY (&xdrs);
diff --git a/sunrpc/svc_tcp.c b/sunrpc/svc_tcp.c
index 75fa8705b6..0c2ce9650a 100644
--- a/sunrpc/svc_tcp.c
+++ b/sunrpc/svc_tcp.c
@@ -141,7 +141,7 @@ svctcp_create (int sock, u_int sendsize, u_int recvsize)
{
if ((sock = __socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
- perror (_("svctcp_.c - udp socket creation problem"));
+ perror (_("svc_tcp.c - tcp socket creation problem"));
return (SVCXPRT *) NULL;
}
madesock = TRUE;
@@ -156,7 +156,7 @@ svctcp_create (int sock, u_int sendsize, u_int recvsize)
if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) ||
(listen (sock, 2) != 0))
{
- perror (_("svctcp_.c - cannot getsockname or listen"));
+ perror (_("svc_tcp.c - cannot getsockname or listen"));
if (madesock)
(void) __close (sock);
return (SVCXPRT *) NULL;
diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c
new file mode 100644
index 0000000000..59ae7a54e7
--- /dev/null
+++ b/sunrpc/svc_unix.c
@@ -0,0 +1,496 @@
+/*
+ * 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 (addr.sun_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 len, 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;
+
+ setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
+
+ return recvmsg (sock, &msg, 0);
+}
+
+static int
+__msgwrite (int sock, void *buf, size_t cnt)
+{
+#ifndef SCM_CRED
+ /* We cannot implement this reliably. */
+ __set_errno (ENOSYS);
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+ int len;
+
+ 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;
+}