Back to index

glibc  2.9
svc_unix.c
Go to the documentation of this file.
00001 /*
00002  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00003  * unrestricted use provided that this legend is included on all tape
00004  * media and as a part of the software program in whole or part.  Users
00005  * may copy or modify Sun RPC without charge, but are not authorized
00006  * to license or distribute it to anyone else except as part of a product or
00007  * program developed by the user.
00008  *
00009  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00010  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00011  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00012  *
00013  * Sun RPC is provided with no support and without any obligation on the
00014  * part of Sun Microsystems, Inc. to assist in its use, correction,
00015  * modification or enhancement.
00016  *
00017  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00018  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00019  * OR ANY PART THEREOF.
00020  *
00021  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00022  * or profits or other special, indirect and consequential damages, even if
00023  * Sun has been advised of the possibility of such damages.
00024  *
00025  * Sun Microsystems, Inc.
00026  * 2550 Garcia Avenue
00027  * Mountain View, California  94043
00028  */
00029 
00030 /*
00031  * svc_unix.c, Server side for TCP/IP based RPC.
00032  *
00033  * Copyright (C) 1984, Sun Microsystems, Inc.
00034  *
00035  * Actually implements two flavors of transporter -
00036  * a unix rendezvouser (a listener and connection establisher)
00037  * and a record/unix stream.
00038  */
00039 
00040 #include <stdio.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043 #include <rpc/rpc.h>
00044 #include <rpc/svc.h>
00045 #include <sys/socket.h>
00046 #include <sys/uio.h>
00047 #include <sys/poll.h>
00048 #include <errno.h>
00049 #include <stdlib.h>
00050 #include <libintl.h>
00051 
00052 #ifdef USE_IN_LIBIO
00053 # include <wchar.h>
00054 #endif
00055 
00056 /*
00057  * Ops vector for AF_UNIX based rpc service handle
00058  */
00059 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
00060 static enum xprt_stat svcunix_stat (SVCXPRT *);
00061 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
00062 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
00063 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
00064 static void svcunix_destroy (SVCXPRT *);
00065 
00066 static const struct xp_ops svcunix_op =
00067 {
00068   svcunix_recv,
00069   svcunix_stat,
00070   svcunix_getargs,
00071   svcunix_reply,
00072   svcunix_freeargs,
00073   svcunix_destroy
00074 };
00075 
00076 /*
00077  * Ops vector for AF_UNIX rendezvous handler
00078  */
00079 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
00080 static enum xprt_stat rendezvous_stat (SVCXPRT *);
00081 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
00082 
00083 /* This function makes sure abort() relocation goes through PLT
00084    and thus can be lazy bound.  */
00085 static void
00086 svcunix_rendezvous_abort (void)
00087 {
00088   abort ();
00089 };
00090 
00091 static const struct xp_ops svcunix_rendezvous_op =
00092 {
00093   rendezvous_request,
00094   rendezvous_stat,
00095   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
00096   (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
00097   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
00098   svcunix_destroy
00099 };
00100 
00101 static int readunix (char*, char *, int);
00102 static int writeunix (char *, char *, int);
00103 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
00104 
00105 struct unix_rendezvous {        /* kept in xprt->xp_p1 */
00106   u_int sendsize;
00107   u_int recvsize;
00108 };
00109 
00110 struct unix_conn {          /* kept in xprt->xp_p1 */
00111   enum xprt_stat strm_stat;
00112   u_long x_id;
00113   XDR xdrs;
00114   char verf_body[MAX_AUTH_BYTES];
00115 };
00116 
00117 /*
00118  * Usage:
00119  *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
00120  *
00121  * Creates, registers, and returns a (rpc) unix based transporter.
00122  * Once *xprt is initialized, it is registered as a transporter
00123  * see (svc.h, xprt_register).  This routine returns
00124  * a NULL if a problem occurred.
00125  *
00126  * If sock<0 then a socket is created, else sock is used.
00127  * If the socket, sock is not bound to a port then svcunix_create
00128  * binds it to an arbitrary port.  The routine then starts a unix
00129  * listener on the socket's associated port.  In any (successful) case,
00130  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
00131  * associated port number.
00132  *
00133  * Since unix streams do buffered io similar to stdio, the caller can specify
00134  * how big the send and receive buffers are via the second and third parms;
00135  * 0 => use the system default.
00136  */
00137 SVCXPRT *
00138 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
00139 {
00140   bool_t madesock = FALSE;
00141   SVCXPRT *xprt;
00142   struct unix_rendezvous *r;
00143   struct sockaddr_un addr;
00144   socklen_t len = sizeof (struct sockaddr_in);
00145 
00146   if (sock == RPC_ANYSOCK)
00147     {
00148       if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
00149        {
00150          perror (_("svc_unix.c - AF_UNIX socket creation problem"));
00151          return (SVCXPRT *) NULL;
00152        }
00153       madesock = TRUE;
00154     }
00155   memset (&addr, '\0', sizeof (addr));
00156   addr.sun_family = AF_UNIX;
00157   len = strlen (path) + 1;
00158   memcpy (addr.sun_path, path, len);
00159   len += sizeof (addr.sun_family);
00160 
00161   __bind (sock, (struct sockaddr *) &addr, len);
00162 
00163   if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
00164       || __listen (sock, SOMAXCONN) != 0)
00165     {
00166       perror (_("svc_unix.c - cannot getsockname or listen"));
00167       if (madesock)
00168        __close (sock);
00169       return (SVCXPRT *) NULL;
00170     }
00171 
00172   r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
00173   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
00174   if (r == NULL || xprt == NULL)
00175     {
00176       __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
00177       mem_free (r, sizeof (*r));
00178       mem_free (xprt, sizeof (SVCXPRT));
00179       return NULL;
00180     }
00181   r->sendsize = sendsize;
00182   r->recvsize = recvsize;
00183   xprt->xp_p2 = NULL;
00184   xprt->xp_p1 = (caddr_t) r;
00185   xprt->xp_verf = _null_auth;
00186   xprt->xp_ops = &svcunix_rendezvous_op;
00187   xprt->xp_port = -1;
00188   xprt->xp_sock = sock;
00189   xprt_register (xprt);
00190   return xprt;
00191 }
00192 
00193 /*
00194  * Like svunix_create(), except the routine takes any *open* UNIX file
00195  * descriptor as its first input.
00196  */
00197 SVCXPRT *
00198 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
00199 {
00200   return makefd_xprt (fd, sendsize, recvsize);
00201 }
00202 
00203 static SVCXPRT *
00204 internal_function
00205 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
00206 {
00207   SVCXPRT *xprt;
00208   struct unix_conn *cd;
00209 
00210   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
00211   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
00212   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
00213     {
00214       (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
00215                       _("out of memory\n"));
00216       mem_free (xprt, sizeof (SVCXPRT));
00217       mem_free (cd, sizeof (struct unix_conn));
00218       return NULL;
00219     }
00220   cd->strm_stat = XPRT_IDLE;
00221   INTUSE(xdrrec_create) (&(cd->xdrs), sendsize, recvsize,
00222                       (caddr_t) xprt, readunix, writeunix);
00223   xprt->xp_p2 = NULL;
00224   xprt->xp_p1 = (caddr_t) cd;
00225   xprt->xp_verf.oa_base = cd->verf_body;
00226   xprt->xp_addrlen = 0;
00227   xprt->xp_ops = &svcunix_op;      /* truly deals with calls */
00228   xprt->xp_port = 0;        /* this is a connection, not a rendezvouser */
00229   xprt->xp_sock = fd;
00230   xprt_register (xprt);
00231   return xprt;
00232 }
00233 
00234 static bool_t
00235 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
00236 {
00237   int sock;
00238   struct unix_rendezvous *r;
00239   struct sockaddr_un addr;
00240   struct sockaddr_in in_addr;
00241   socklen_t len;
00242 
00243   r = (struct unix_rendezvous *) xprt->xp_p1;
00244 again:
00245   len = sizeof (struct sockaddr_un);
00246   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
00247     {
00248       if (errno == EINTR)
00249        goto again;
00250       return FALSE;
00251     }
00252   /*
00253    * make a new transporter (re-uses xprt)
00254    */
00255   memset (&in_addr, '\0', sizeof (in_addr));
00256   in_addr.sin_family = AF_UNIX;
00257   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
00258   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
00259   xprt->xp_addrlen = len;
00260   return FALSE;             /* there is never an rpc msg to be processed */
00261 }
00262 
00263 static enum xprt_stat
00264 rendezvous_stat (SVCXPRT *xprt)
00265 {
00266   return XPRT_IDLE;
00267 }
00268 
00269 static void
00270 svcunix_destroy (SVCXPRT *xprt)
00271 {
00272   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
00273 
00274   xprt_unregister (xprt);
00275   __close (xprt->xp_sock);
00276   if (xprt->xp_port != 0)
00277     {
00278       /* a rendezvouser socket */
00279       xprt->xp_port = 0;
00280     }
00281   else
00282     {
00283       /* an actual connection socket */
00284       XDR_DESTROY (&(cd->xdrs));
00285     }
00286   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
00287   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
00288 }
00289 
00290 #ifdef SCM_CREDENTIALS
00291 struct cmessage {
00292   struct cmsghdr cmsg;
00293   struct ucred cmcred;
00294   /* hack to make sure we have enough memory */
00295   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
00296 };
00297 
00298 /* XXX This is not thread safe, but since the main functions in svc.c
00299    and the rpcgen generated *_svc functions for the daemon are also not
00300    thread safe and uses static global variables, it doesn't matter. */
00301 static struct cmessage cm;
00302 #endif
00303 
00304 static int
00305 __msgread (int sock, void *data, size_t cnt)
00306 {
00307   struct iovec iov;
00308   struct msghdr msg;
00309   int len;
00310 
00311   iov.iov_base = data;
00312   iov.iov_len = cnt;
00313 
00314   msg.msg_iov = &iov;
00315   msg.msg_iovlen = 1;
00316   msg.msg_name = NULL;
00317   msg.msg_namelen = 0;
00318 #ifdef SCM_CREDENTIALS
00319   msg.msg_control = (caddr_t) &cm;
00320   msg.msg_controllen = sizeof (struct cmessage);
00321 #endif
00322   msg.msg_flags = 0;
00323 
00324 #ifdef SO_PASSCRED
00325   {
00326     int on = 1;
00327     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
00328       return -1;
00329   }
00330 #endif
00331 
00332  restart:
00333   len = __recvmsg (sock, &msg, 0);
00334   if (len >= 0)
00335     {
00336       if (msg.msg_flags & MSG_CTRUNC || len == 0)
00337         return 0;
00338       else
00339         return len;
00340     }
00341   if (errno == EINTR)
00342     goto restart;
00343   return -1;
00344 }
00345 
00346 static int
00347 __msgwrite (int sock, void *data, size_t cnt)
00348 {
00349 #ifndef SCM_CREDENTIALS
00350   /* We cannot implement this reliably.  */
00351   __set_errno (ENOSYS);
00352   return -1;
00353 #else
00354   struct iovec iov;
00355   struct msghdr msg;
00356   struct cmsghdr *cmsg = &cm.cmsg;
00357   struct ucred cred;
00358   int len;
00359 
00360   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
00361      get?id(). But since keyserv needs geteuid(), we have no other chance.
00362      It would be much better, if the kernel could pass both to the server. */
00363   cred.pid = __getpid ();
00364   cred.uid = __geteuid ();
00365   cred.gid = __getegid ();
00366 
00367   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
00368   cmsg->cmsg_level = SOL_SOCKET;
00369   cmsg->cmsg_type = SCM_CREDENTIALS;
00370   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
00371 
00372   iov.iov_base = data;
00373   iov.iov_len = cnt;
00374 
00375   msg.msg_iov = &iov;
00376   msg.msg_iovlen = 1;
00377   msg.msg_name = NULL;
00378   msg.msg_namelen = 0;
00379   msg.msg_control = cmsg;
00380   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
00381   msg.msg_flags = 0;
00382 
00383  restart:
00384   len = __sendmsg (sock, &msg, 0);
00385   if (len >= 0)
00386     return len;
00387   if (errno == EINTR)
00388     goto restart;
00389   return -1;
00390 
00391 #endif
00392 }
00393 
00394 /*
00395  * reads data from the unix connection.
00396  * any error is fatal and the connection is closed.
00397  * (And a read of zero bytes is a half closed stream => error.)
00398  */
00399 static int
00400 readunix (char *xprtptr, char *buf, int len)
00401 {
00402   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
00403   int sock = xprt->xp_sock;
00404   int milliseconds = 35 * 1000;
00405   struct pollfd pollfd;
00406 
00407   do
00408     {
00409       pollfd.fd = sock;
00410       pollfd.events = POLLIN;
00411       switch (__poll (&pollfd, 1, milliseconds))
00412        {
00413        case -1:
00414          if (errno == EINTR)
00415            continue;
00416          /*FALLTHROUGH*/
00417        case 0:
00418          goto fatal_err;
00419        default:
00420          if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
00421              || (pollfd.revents & POLLNVAL))
00422            goto fatal_err;
00423          break;
00424        }
00425     }
00426   while ((pollfd.revents & POLLIN) == 0);
00427 
00428   if ((len = __msgread (sock, buf, len)) > 0)
00429     return len;
00430 
00431  fatal_err:
00432   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
00433   return -1;
00434 }
00435 
00436 /*
00437  * writes data to the unix connection.
00438  * Any error is fatal and the connection is closed.
00439  */
00440 static int
00441 writeunix (char *xprtptr, char * buf, int len)
00442 {
00443   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
00444   int i, cnt;
00445 
00446   for (cnt = len; cnt > 0; cnt -= i, buf += i)
00447     {
00448       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
00449        {
00450          ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
00451          return -1;
00452        }
00453     }
00454   return len;
00455 }
00456 
00457 static enum xprt_stat
00458 svcunix_stat (SVCXPRT *xprt)
00459 {
00460   struct unix_conn *cd =
00461   (struct unix_conn *) (xprt->xp_p1);
00462 
00463   if (cd->strm_stat == XPRT_DIED)
00464     return XPRT_DIED;
00465   if (!INTUSE(xdrrec_eof) (&(cd->xdrs)))
00466     return XPRT_MOREREQS;
00467   return XPRT_IDLE;
00468 }
00469 
00470 static bool_t
00471 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
00472 {
00473   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
00474   XDR *xdrs = &(cd->xdrs);
00475 
00476   xdrs->x_op = XDR_DECODE;
00477   INTUSE(xdrrec_skiprecord) (xdrs);
00478   if (INTUSE(xdr_callmsg) (xdrs, msg))
00479     {
00480       cd->x_id = msg->rm_xid;
00481       /* set up verifiers */
00482 #ifdef SCM_CREDENTIALS
00483       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
00484       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
00485       msg->rm_call.cb_verf.oa_length = sizeof (cm);
00486 #endif
00487       return TRUE;
00488     }
00489   cd->strm_stat = XPRT_DIED;       /* XXXX */
00490   return FALSE;
00491 }
00492 
00493 static bool_t
00494 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
00495 {
00496   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
00497                     args_ptr);
00498 }
00499 
00500 static bool_t
00501 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
00502 {
00503   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
00504 
00505   xdrs->x_op = XDR_FREE;
00506   return (*xdr_args) (xdrs, args_ptr);
00507 }
00508 
00509 static bool_t
00510 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
00511 {
00512   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
00513   XDR *xdrs = &(cd->xdrs);
00514   bool_t stat;
00515 
00516   xdrs->x_op = XDR_ENCODE;
00517   msg->rm_xid = cd->x_id;
00518   stat = INTUSE(xdr_replymsg) (xdrs, msg);
00519   (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
00520   return stat;
00521 }