Back to index

glibc  2.9
clnt_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  * clnt_unix.c, Implements a TCP/IP based, client side RPC.
00032  *
00033  * Copyright (C) 1984, Sun Microsystems, Inc.
00034  *
00035  * TCP based RPC supports 'batched calls'.
00036  * A sequence of calls may be batched-up in a send buffer.  The rpc call
00037  * return immediately to the client even though the call was not necessarily
00038  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
00039  * the rpc timeout value is zero (see clnt.h, rpc).
00040  *
00041  * Clients should NOT casually batch calls that in fact return results; that is,
00042  * the server side should be aware that a call is batched and not produce any
00043  * return message.  Batched calls that produce many result messages can
00044  * deadlock (netlock) the client and the server....
00045  *
00046  * Now go hang yourself.
00047  */
00048 
00049 #include <netdb.h>
00050 #include <errno.h>
00051 #include <stdio.h>
00052 #include <unistd.h>
00053 #include <libintl.h>
00054 #include <rpc/rpc.h>
00055 #include <sys/uio.h>
00056 #include <sys/poll.h>
00057 #include <sys/socket.h>
00058 #include <rpc/pmap_clnt.h>
00059 #ifdef USE_IN_LIBIO
00060 # include <wchar.h>
00061 #endif
00062 
00063 extern u_long _create_xid (void);
00064 
00065 #define MCALL_MSG_SIZE 24
00066 
00067 struct ct_data
00068   {
00069     int ct_sock;
00070     bool_t ct_closeit;
00071     struct timeval ct_wait;
00072     bool_t ct_waitset;             /* wait set by clnt_control? */
00073     struct sockaddr_un ct_addr;
00074     struct rpc_err ct_error;
00075     char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
00076     u_int ct_mpos;          /* pos after marshal */
00077     XDR ct_xdrs;
00078   };
00079 
00080 static int readunix (char *, char *, int);
00081 static int writeunix (char *, char *, int);
00082 
00083 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
00084                                 xdrproc_t, caddr_t, struct timeval);
00085 static void clntunix_abort (void);
00086 static void clntunix_geterr (CLIENT *, struct rpc_err *);
00087 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
00088 static bool_t clntunix_control (CLIENT *, int, char *);
00089 static void clntunix_destroy (CLIENT *);
00090 
00091 static const struct clnt_ops unix_ops =
00092 {
00093   clntunix_call,
00094   clntunix_abort,
00095   clntunix_geterr,
00096   clntunix_freeres,
00097   clntunix_destroy,
00098   clntunix_control
00099 };
00100 
00101 /*
00102  * Create a client handle for a tcp/ip connection.
00103  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
00104  * connected to raddr.  If *sockp non-negative then
00105  * raddr is ignored.  The rpc/tcp package does buffering
00106  * similar to stdio, so the client must pick send and receive buffer sizes,];
00107  * 0 => use the default.
00108  * If raddr->sin_port is 0, then a binder on the remote machine is
00109  * consulted for the right port number.
00110  * NB: *sockp is copied into a private area.
00111  * NB: It is the clients responsibility to close *sockp.
00112  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
00113  * something more useful.
00114  */
00115 CLIENT *
00116 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
00117                int *sockp, u_int sendsz, u_int recvsz)
00118 {
00119   CLIENT *h;
00120   struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
00121   struct rpc_msg call_msg;
00122   int len;
00123 
00124   h = (CLIENT *) mem_alloc (sizeof (*h));
00125   if (h == NULL || ct == NULL)
00126     {
00127       struct rpc_createerr *ce = &get_rpc_createerr ();
00128       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
00129       ce->cf_stat = RPC_SYSTEMERROR;
00130       ce->cf_error.re_errno = ENOMEM;
00131       goto fooy;
00132     }
00133 
00134   /*
00135    * If no socket given, open one
00136    */
00137   if (*sockp < 0)
00138     {
00139       *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
00140       len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
00141       if (*sockp < 0
00142          || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
00143        {
00144          struct rpc_createerr *ce = &get_rpc_createerr ();
00145          ce->cf_stat = RPC_SYSTEMERROR;
00146          ce->cf_error.re_errno = errno;
00147          if (*sockp != -1)
00148            __close (*sockp);
00149          goto fooy;
00150        }
00151       ct->ct_closeit = TRUE;
00152     }
00153   else
00154     {
00155       ct->ct_closeit = FALSE;
00156     }
00157 
00158   /*
00159    * Set up private data struct
00160    */
00161   ct->ct_sock = *sockp;
00162   ct->ct_wait.tv_usec = 0;
00163   ct->ct_waitset = FALSE;
00164   ct->ct_addr = *raddr;
00165 
00166   /*
00167    * Initialize call message
00168    */
00169   call_msg.rm_xid = _create_xid ();
00170   call_msg.rm_direction = CALL;
00171   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
00172   call_msg.rm_call.cb_prog = prog;
00173   call_msg.rm_call.cb_vers = vers;
00174 
00175   /*
00176    * pre-serialize the static part of the call msg and stash it away
00177    */
00178   INTUSE(xdrmem_create) (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
00179                       XDR_ENCODE);
00180   if (!INTUSE(xdr_callhdr) (&(ct->ct_xdrs), &call_msg))
00181     {
00182       if (ct->ct_closeit)
00183        __close (*sockp);
00184       goto fooy;
00185     }
00186   ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
00187   XDR_DESTROY (&(ct->ct_xdrs));
00188 
00189   /*
00190    * Create a client handle which uses xdrrec for serialization
00191    * and authnone for authentication.
00192    */
00193   INTUSE(xdrrec_create) (&(ct->ct_xdrs), sendsz, recvsz,
00194                       (caddr_t) ct, readunix, writeunix);
00195   h->cl_ops = (struct clnt_ops *) &unix_ops;
00196   h->cl_private = (caddr_t) ct;
00197   h->cl_auth = INTUSE(authnone_create) ();
00198   return h;
00199 
00200 fooy:
00201   /*
00202    * Something goofed, free stuff and barf
00203    */
00204   mem_free ((caddr_t) ct, sizeof (struct ct_data));
00205   mem_free ((caddr_t) h, sizeof (CLIENT));
00206   return (CLIENT *) NULL;
00207 }
00208 INTDEF (clntunix_create)
00209 
00210 static enum clnt_stat
00211 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
00212      CLIENT *h;
00213      u_long proc;
00214      xdrproc_t xdr_args;
00215      caddr_t args_ptr;
00216      xdrproc_t xdr_results;
00217      caddr_t results_ptr;
00218      struct timeval timeout;
00219 {
00220   struct ct_data *ct = (struct ct_data *) h->cl_private;
00221   XDR *xdrs = &(ct->ct_xdrs);
00222   struct rpc_msg reply_msg;
00223   u_long x_id;
00224   u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
00225   bool_t shipnow;
00226   int refreshes = 2;
00227 
00228   if (!ct->ct_waitset)
00229     {
00230       ct->ct_wait = timeout;
00231     }
00232 
00233   shipnow =
00234     (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
00235      && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
00236 
00237 call_again:
00238   xdrs->x_op = XDR_ENCODE;
00239   ct->ct_error.re_status = RPC_SUCCESS;
00240   x_id = ntohl (--(*msg_x_id));
00241   if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
00242       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
00243       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
00244       (!(*xdr_args) (xdrs, args_ptr)))
00245     {
00246       if (ct->ct_error.re_status == RPC_SUCCESS)
00247        ct->ct_error.re_status = RPC_CANTENCODEARGS;
00248       (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
00249       return ct->ct_error.re_status;
00250     }
00251   if (!INTUSE(xdrrec_endofrecord) (xdrs, shipnow))
00252     return ct->ct_error.re_status = RPC_CANTSEND;
00253   if (!shipnow)
00254     return RPC_SUCCESS;
00255   /*
00256    * Hack to provide rpc-based message passing
00257    */
00258   if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
00259     return ct->ct_error.re_status = RPC_TIMEDOUT;
00260 
00261 
00262   /*
00263    * Keep receiving until we get a valid transaction id
00264    */
00265   xdrs->x_op = XDR_DECODE;
00266   while (TRUE)
00267     {
00268       reply_msg.acpted_rply.ar_verf = _null_auth;
00269       reply_msg.acpted_rply.ar_results.where = NULL;
00270       reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)INTUSE(xdr_void);
00271       if (!INTUSE(xdrrec_skiprecord) (xdrs))
00272        return ct->ct_error.re_status;
00273       /* now decode and validate the response header */
00274       if (!INTUSE(xdr_replymsg) (xdrs, &reply_msg))
00275        {
00276          if (ct->ct_error.re_status == RPC_SUCCESS)
00277            continue;
00278          return ct->ct_error.re_status;
00279        }
00280       if (reply_msg.rm_xid == x_id)
00281        break;
00282     }
00283 
00284   /*
00285    * process header
00286    */
00287   _seterr_reply (&reply_msg, &(ct->ct_error));
00288   if (ct->ct_error.re_status == RPC_SUCCESS)
00289     {
00290       if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
00291        {
00292          ct->ct_error.re_status = RPC_AUTHERROR;
00293          ct->ct_error.re_why = AUTH_INVALIDRESP;
00294        }
00295       else if (!(*xdr_results) (xdrs, results_ptr))
00296        {
00297          if (ct->ct_error.re_status == RPC_SUCCESS)
00298            ct->ct_error.re_status = RPC_CANTDECODERES;
00299        }
00300       /* free verifier ... */
00301       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
00302        {
00303          xdrs->x_op = XDR_FREE;
00304          (void) INTUSE(xdr_opaque_auth) (xdrs,
00305                                      &(reply_msg.acpted_rply.ar_verf));
00306        }
00307     }                       /* end successful completion */
00308   else
00309     {
00310       /* maybe our credentials need to be refreshed ... */
00311       if (refreshes-- && AUTH_REFRESH (h->cl_auth))
00312        goto call_again;
00313     }                       /* end of unsuccessful completion */
00314   return ct->ct_error.re_status;
00315 }
00316 
00317 static void
00318 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
00319 {
00320   struct ct_data *ct = (struct ct_data *) h->cl_private;
00321 
00322   *errp = ct->ct_error;
00323 }
00324 
00325 static bool_t
00326 clntunix_freeres (cl, xdr_res, res_ptr)
00327      CLIENT *cl;
00328      xdrproc_t xdr_res;
00329      caddr_t res_ptr;
00330 {
00331   struct ct_data *ct = (struct ct_data *) cl->cl_private;
00332   XDR *xdrs = &(ct->ct_xdrs);
00333 
00334   xdrs->x_op = XDR_FREE;
00335   return (*xdr_res) (xdrs, res_ptr);
00336 }
00337 
00338 static void
00339 clntunix_abort ()
00340 {
00341 }
00342 
00343 static bool_t
00344 clntunix_control (CLIENT *cl, int request, char *info)
00345 {
00346   struct ct_data *ct = (struct ct_data *) cl->cl_private;
00347 
00348 
00349   switch (request)
00350     {
00351     case CLSET_FD_CLOSE:
00352       ct->ct_closeit = TRUE;
00353       break;
00354     case CLSET_FD_NCLOSE:
00355       ct->ct_closeit = FALSE;
00356       break;
00357     case CLSET_TIMEOUT:
00358       ct->ct_wait = *(struct timeval *) info;
00359       break;
00360     case CLGET_TIMEOUT:
00361       *(struct timeval *) info = ct->ct_wait;
00362       break;
00363     case CLGET_SERVER_ADDR:
00364       *(struct sockaddr_un *) info = ct->ct_addr;
00365       break;
00366     case CLGET_FD:
00367       *(int *)info = ct->ct_sock;
00368       break;
00369     case CLGET_XID:
00370       /*
00371        * use the knowledge that xid is the
00372        * first element in the call structure *.
00373        * This will get the xid of the PREVIOUS call
00374        */
00375       *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
00376       break;
00377     case CLSET_XID:
00378       /* This will set the xid of the NEXT call */
00379       *(u_long *) ct->ct_mcall =  htonl (*(u_long *)info - 1);
00380       /* decrement by 1 as clntunix_call() increments once */
00381     case CLGET_VERS:
00382       /*
00383        * This RELIES on the information that, in the call body,
00384        * the version number field is the fifth field from the
00385        * begining of the RPC header. MUST be changed if the
00386        * call_struct is changed
00387        */
00388       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
00389                                         + 4 * BYTES_PER_XDR_UNIT));
00390       break;
00391     case CLSET_VERS:
00392       *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
00393        = htonl (*(u_long *) info);
00394       break;
00395     case CLGET_PROG:
00396       /*
00397        * This RELIES on the information that, in the call body,
00398        * the program number field is the  field from the
00399        * begining of the RPC header. MUST be changed if the
00400        * call_struct is changed
00401        */
00402       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
00403                                         + 3 * BYTES_PER_XDR_UNIT));
00404       break;
00405     case CLSET_PROG:
00406       *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
00407        = htonl(*(u_long *) info);
00408       break;
00409     /* The following are only possible with TI-RPC */
00410     case CLGET_RETRY_TIMEOUT:
00411     case CLSET_RETRY_TIMEOUT:
00412     case CLGET_SVC_ADDR:
00413     case CLSET_SVC_ADDR:
00414     case CLSET_PUSH_TIMOD:
00415     case CLSET_POP_TIMOD:
00416     default:
00417       return FALSE;
00418     }
00419   return TRUE;
00420 }
00421 
00422 
00423 static void
00424 clntunix_destroy (CLIENT *h)
00425 {
00426   struct ct_data *ct =
00427   (struct ct_data *) h->cl_private;
00428 
00429   if (ct->ct_closeit)
00430     {
00431       (void) __close (ct->ct_sock);
00432     }
00433   XDR_DESTROY (&(ct->ct_xdrs));
00434   mem_free ((caddr_t) ct, sizeof (struct ct_data));
00435   mem_free ((caddr_t) h, sizeof (CLIENT));
00436 }
00437 
00438 static int
00439 __msgread (int sock, void *data, size_t cnt)
00440 {
00441   struct iovec iov;
00442   struct msghdr msg;
00443 #ifdef SCM_CREDENTIALS
00444   static char cm[CMSG_SPACE(sizeof (struct ucred))];
00445 #endif
00446   int len;
00447 
00448   iov.iov_base = data;
00449   iov.iov_len = cnt;
00450 
00451   msg.msg_iov = &iov;
00452   msg.msg_iovlen = 1;
00453   msg.msg_name = NULL;
00454   msg.msg_namelen = 0;
00455 #ifdef SCM_CREDENTIALS
00456   msg.msg_control = (caddr_t) &cm;
00457   msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
00458 #endif
00459   msg.msg_flags = 0;
00460 
00461 #ifdef SO_PASSCRED
00462   {
00463     int on = 1;
00464     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
00465       return -1;
00466   }
00467 #endif
00468 
00469  restart:
00470   len = __recvmsg (sock, &msg, 0);
00471   if (len >= 0)
00472     {
00473       if (msg.msg_flags & MSG_CTRUNC || len == 0)
00474        return 0;
00475       else
00476        return len;
00477     }
00478   if (errno == EINTR)
00479     goto restart;
00480   return -1;
00481 }
00482 
00483 static int
00484 __msgwrite (int sock, void *data, size_t cnt)
00485 {
00486 #ifndef SCM_CREDENTIALS
00487   /* We cannot implement this reliably.  */
00488   __set_errno (ENOSYS);
00489   return -1;
00490 #else
00491   struct iovec iov;
00492   struct msghdr msg;
00493   struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
00494   struct ucred cred;
00495   int len;
00496 
00497   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
00498      get?id(). But since keyserv needs geteuid(), we have no other chance.
00499      It would be much better, if the kernel could pass both to the server. */
00500   cred.pid = __getpid ();
00501   cred.uid = __geteuid ();
00502   cred.gid = __getegid ();
00503 
00504   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
00505   cmsg->cmsg_level = SOL_SOCKET;
00506   cmsg->cmsg_type = SCM_CREDENTIALS;
00507   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
00508 
00509   iov.iov_base = data;
00510   iov.iov_len = cnt;
00511 
00512   msg.msg_iov = &iov;
00513   msg.msg_iovlen = 1;
00514   msg.msg_name = NULL;
00515   msg.msg_namelen = 0;
00516   msg.msg_control = cmsg;
00517   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
00518   msg.msg_flags = 0;
00519 
00520  restart:
00521   len = __sendmsg (sock, &msg, 0);
00522   if (len >= 0)
00523     return len;
00524   if (errno == EINTR)
00525     goto restart;
00526   return -1;
00527 
00528 #endif
00529 }
00530 
00531 
00532 /*
00533  * Interface between xdr serializer and unix connection.
00534  * Behaves like the system calls, read & write, but keeps some error state
00535  * around for the rpc level.
00536  */
00537 static int
00538 readunix (char *ctptr, char *buf, int len)
00539 {
00540   struct ct_data *ct = (struct ct_data *) ctptr;
00541   struct pollfd fd;
00542   int milliseconds = ((ct->ct_wait.tv_sec * 1000)
00543                     + (ct->ct_wait.tv_usec / 1000));
00544 
00545   if (len == 0)
00546     return 0;
00547 
00548   fd.fd = ct->ct_sock;
00549   fd.events = POLLIN;
00550   while (TRUE)
00551     {
00552       switch (__poll (&fd, 1, milliseconds))
00553         {
00554         case 0:
00555           ct->ct_error.re_status = RPC_TIMEDOUT;
00556           return -1;
00557 
00558         case -1:
00559           if (errno == EINTR)
00560             continue;
00561           ct->ct_error.re_status = RPC_CANTRECV;
00562           ct->ct_error.re_errno = errno;
00563           return -1;
00564         }
00565       break;
00566     }
00567   switch (len = __msgread (ct->ct_sock, buf, len))
00568     {
00569 
00570     case 0:
00571       /* premature eof */
00572       ct->ct_error.re_errno = ECONNRESET;
00573       ct->ct_error.re_status = RPC_CANTRECV;
00574       len = -1;                    /* it's really an error */
00575       break;
00576 
00577     case -1:
00578       ct->ct_error.re_errno = errno;
00579       ct->ct_error.re_status = RPC_CANTRECV;
00580       break;
00581     }
00582   return len;
00583 }
00584 
00585 static int
00586 writeunix (char *ctptr, char *buf, int len)
00587 {
00588   int i, cnt;
00589   struct ct_data *ct = (struct ct_data *) ctptr;
00590 
00591   for (cnt = len; cnt > 0; cnt -= i, buf += i)
00592     {
00593       if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
00594        {
00595          ct->ct_error.re_errno = errno;
00596          ct->ct_error.re_status = RPC_CANTSEND;
00597          return -1;
00598        }
00599     }
00600   return len;
00601 }