clnt_vc.c revision 266245
1243791Sdim/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 2243791Sdim 3243791Sdim/*- 4243791Sdim * Copyright (c) 2009, Sun Microsystems, Inc. 5243791Sdim * All rights reserved. 6243791Sdim * 7243791Sdim * Redistribution and use in source and binary forms, with or without 8243791Sdim * modification, are permitted provided that the following conditions are met: 9243791Sdim * - Redistributions of source code must retain the above copyright notice, 10243791Sdim * this list of conditions and the following disclaimer. 11243791Sdim * - Redistributions in binary form must reproduce the above copyright notice, 12243791Sdim * this list of conditions and the following disclaimer in the documentation 13243791Sdim * and/or other materials provided with the distribution. 14243791Sdim * - Neither the name of Sun Microsystems, Inc. nor the names of its 15243791Sdim * contributors may be used to endorse or promote products derived 16243791Sdim * from this software without specific prior written permission. 17252723Sdim * 18243791Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252723Sdim * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252723Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252723Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22243791Sdim * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23243791Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252723Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252723Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252723Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252723Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252723Sdim * POSSIBILITY OF SUCH DAMAGE. 29243791Sdim */ 30243791Sdim 31243791Sdim#if defined(LIBC_SCCS) && !defined(lint) 32243791Sdimstatic char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 33243791Sdimstatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34243791Sdimstatic char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 35243791Sdim#endif 36243791Sdim#include <sys/cdefs.h> 37243791Sdim__FBSDID("$FreeBSD: stable/9/lib/libc/rpc/clnt_vc.c 266245 2014-05-16 15:51:37Z brueffer $"); 38243791Sdim 39243791Sdim/* 40243791Sdim * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 41243791Sdim * 42243791Sdim * Copyright (C) 1984, Sun Microsystems, Inc. 43243791Sdim * 44243791Sdim * TCP based RPC supports 'batched calls'. 45243791Sdim * A sequence of calls may be batched-up in a send buffer. The rpc call 46243791Sdim * return immediately to the client even though the call was not necessarily 47243791Sdim * sent. The batching occurs if the results' xdr routine is NULL (0) AND 48243791Sdim * the rpc timeout value is zero (see clnt.h, rpc). 49243791Sdim * 50243791Sdim * Clients should NOT casually batch calls that in fact return results; that is, 51243791Sdim * the server side should be aware that a call is batched and not produce any 52243791Sdim * return message. Batched calls that produce many result messages can 53243791Sdim * deadlock (netlock) the client and the server.... 54243791Sdim * 55243791Sdim * Now go hang yourself. 56243791Sdim */ 57243791Sdim 58243791Sdim#include "namespace.h" 59243791Sdim#include "reentrant.h" 60243791Sdim#include <sys/types.h> 61243791Sdim#include <sys/poll.h> 62243791Sdim#include <sys/syslog.h> 63243791Sdim#include <sys/socket.h> 64243791Sdim#include <sys/un.h> 65243791Sdim#include <sys/uio.h> 66243791Sdim 67243791Sdim#include <arpa/inet.h> 68243791Sdim#include <assert.h> 69243791Sdim#include <err.h> 70243791Sdim#include <errno.h> 71243791Sdim#include <netdb.h> 72243791Sdim#include <stdio.h> 73243791Sdim#include <stdlib.h> 74243791Sdim#include <string.h> 75243791Sdim#include <unistd.h> 76243791Sdim#include <signal.h> 77243791Sdim 78243791Sdim#include <rpc/rpc.h> 79243791Sdim#include <rpc/rpcsec_gss.h> 80243791Sdim#include "un-namespace.h" 81243791Sdim#include "rpc_com.h" 82243791Sdim#include "mt_misc.h" 83243791Sdim 84243791Sdim#define MCALL_MSG_SIZE 24 85243791Sdim 86243791Sdimstruct cmessage { 87243791Sdim struct cmsghdr cmsg; 88243791Sdim struct cmsgcred cmcred; 89243791Sdim}; 90243791Sdim 91243791Sdimstatic enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 92243791Sdim xdrproc_t, void *, struct timeval); 93243791Sdimstatic void clnt_vc_geterr(CLIENT *, struct rpc_err *); 94243791Sdimstatic bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); 95243791Sdimstatic void clnt_vc_abort(CLIENT *); 96243791Sdimstatic bool_t clnt_vc_control(CLIENT *, u_int, void *); 97243791Sdimstatic void clnt_vc_destroy(CLIENT *); 98243791Sdimstatic struct clnt_ops *clnt_vc_ops(void); 99243791Sdimstatic bool_t time_not_ok(struct timeval *); 100243791Sdimstatic int read_vc(void *, void *, int); 101243791Sdimstatic int write_vc(void *, void *, int); 102243791Sdimstatic int __msgwrite(int, void *, size_t); 103263509Sdimstatic int __msgread(int, void *, size_t); 104243791Sdim 105243791Sdimstruct ct_data { 106243791Sdim int ct_fd; /* connection's fd */ 107243791Sdim bool_t ct_closeit; /* close it on destroy */ 108243791Sdim struct timeval ct_wait; /* wait interval in milliseconds */ 109243791Sdim bool_t ct_waitset; /* wait set by clnt_control? */ 110243791Sdim struct netbuf ct_addr; /* remote addr */ 111243791Sdim struct rpc_err ct_error; 112243791Sdim union { 113243791Sdim char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 114243791Sdim u_int32_t ct_mcalli; 115243791Sdim } ct_u; 116243791Sdim u_int ct_mpos; /* pos after marshal */ 117243791Sdim XDR ct_xdrs; /* XDR stream */ 118243791Sdim}; 119243791Sdim 120243791Sdim/* 121243791Sdim * This machinery implements per-fd locks for MT-safety. It is not 122243791Sdim * sufficient to do per-CLIENT handle locks for MT-safety because a 123243791Sdim * user may create more than one CLIENT handle with the same fd behind 124243791Sdim * it. Therfore, we allocate an array of flags (vc_fd_locks), protected 125243791Sdim * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables 126243791Sdim * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some 127243791Sdim * CLIENT handle created for that fd. 128243791Sdim * The current implementation holds locks across the entire RPC and reply. 129243791Sdim * Yes, this is silly, and as soon as this code is proven to work, this 130243791Sdim * should be the first thing fixed. One step at a time. 131243791Sdim */ 132243791Sdimstatic int *vc_fd_locks; 133243791Sdimstatic cond_t *vc_cv; 134243791Sdim#define release_fd_lock(fd, mask) { \ 135243791Sdim mutex_lock(&clnt_fd_lock); \ 136243791Sdim vc_fd_locks[fd] = 0; \ 137243791Sdim mutex_unlock(&clnt_fd_lock); \ 138243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 139243791Sdim cond_signal(&vc_cv[fd]); \ 140243791Sdim} 141243791Sdim 142243791Sdimstatic const char clnt_vc_errstr[] = "%s : %s"; 143243791Sdimstatic const char clnt_vc_str[] = "clnt_vc_create"; 144243791Sdimstatic const char clnt_read_vc_str[] = "read_vc"; 145243791Sdimstatic const char __no_mem_str[] = "out of memory"; 146243791Sdim 147243791Sdim/* 148243791Sdim * Create a client handle for a connection. 149243791Sdim * Default options are set, which the user can change using clnt_control()'s. 150243791Sdim * The rpc/vc package does buffering similar to stdio, so the client 151243791Sdim * must pick send and receive buffer sizes, 0 => use the default. 152243791Sdim * NB: fd is copied into a private area. 153243791Sdim * NB: The rpch->cl_auth is set null authentication. Caller may wish to 154243791Sdim * set this something more useful. 155243791Sdim * 156243791Sdim * fd should be an open socket 157243791Sdim */ 158243791SdimCLIENT * 159243791Sdimclnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) 160243791Sdim int fd; /* open file descriptor */ 161243791Sdim const struct netbuf *raddr; /* servers address */ 162243791Sdim const rpcprog_t prog; /* program number */ 163243791Sdim const rpcvers_t vers; /* version number */ 164243791Sdim u_int sendsz; /* buffer recv size */ 165243791Sdim u_int recvsz; /* buffer send size */ 166243791Sdim{ 167243791Sdim CLIENT *cl; /* client handle */ 168243791Sdim struct ct_data *ct = NULL; /* client handle */ 169243791Sdim struct timeval now; 170243791Sdim struct rpc_msg call_msg; 171243791Sdim static u_int32_t disrupt; 172243791Sdim sigset_t mask; 173243791Sdim sigset_t newmask; 174243791Sdim struct sockaddr_storage ss; 175243791Sdim socklen_t slen; 176243791Sdim struct __rpc_sockinfo si; 177243791Sdim 178243791Sdim if (disrupt == 0) 179243791Sdim disrupt = (u_int32_t)(long)raddr; 180243791Sdim 181243791Sdim cl = (CLIENT *)mem_alloc(sizeof (*cl)); 182243791Sdim ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 183243791Sdim if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { 184243791Sdim (void) syslog(LOG_ERR, clnt_vc_errstr, 185243791Sdim clnt_vc_str, __no_mem_str); 186243791Sdim rpc_createerr.cf_stat = RPC_SYSTEMERROR; 187243791Sdim rpc_createerr.cf_error.re_errno = errno; 188243791Sdim goto err; 189243791Sdim } 190243791Sdim ct->ct_addr.buf = NULL; 191243791Sdim sigfillset(&newmask); 192243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 193243791Sdim mutex_lock(&clnt_fd_lock); 194243791Sdim if (vc_fd_locks == (int *) NULL) { 195243791Sdim int cv_allocsz, fd_allocsz; 196243791Sdim int dtbsize = __rpc_dtbsize(); 197243791Sdim 198243791Sdim fd_allocsz = dtbsize * sizeof (int); 199243791Sdim vc_fd_locks = (int *) mem_alloc(fd_allocsz); 200243791Sdim if (vc_fd_locks == (int *) NULL) { 201243791Sdim mutex_unlock(&clnt_fd_lock); 202243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 203243791Sdim goto err; 204243791Sdim } else 205243791Sdim memset(vc_fd_locks, '\0', fd_allocsz); 206243791Sdim 207243791Sdim assert(vc_cv == (cond_t *) NULL); 208243791Sdim cv_allocsz = dtbsize * sizeof (cond_t); 209243791Sdim vc_cv = (cond_t *) mem_alloc(cv_allocsz); 210243791Sdim if (vc_cv == (cond_t *) NULL) { 211243791Sdim mem_free(vc_fd_locks, fd_allocsz); 212243791Sdim vc_fd_locks = (int *) NULL; 213243791Sdim mutex_unlock(&clnt_fd_lock); 214243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 215243791Sdim goto err; 216243791Sdim } else { 217243791Sdim int i; 218243791Sdim 219243791Sdim for (i = 0; i < dtbsize; i++) 220243791Sdim cond_init(&vc_cv[i], 0, (void *) 0); 221243791Sdim } 222243791Sdim } else 223243791Sdim assert(vc_cv != (cond_t *) NULL); 224243791Sdim 225243791Sdim /* 226243791Sdim * XXX - fvdl connecting while holding a mutex? 227243791Sdim */ 228243791Sdim slen = sizeof ss; 229243791Sdim if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 230243791Sdim if (errno != ENOTCONN) { 231243791Sdim rpc_createerr.cf_stat = RPC_SYSTEMERROR; 232243791Sdim rpc_createerr.cf_error.re_errno = errno; 233243791Sdim mutex_unlock(&clnt_fd_lock); 234243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 235243791Sdim goto err; 236243791Sdim } 237243791Sdim if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 238243791Sdim rpc_createerr.cf_stat = RPC_SYSTEMERROR; 239243791Sdim rpc_createerr.cf_error.re_errno = errno; 240243791Sdim mutex_unlock(&clnt_fd_lock); 241243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 242243791Sdim goto err; 243243791Sdim } 244243791Sdim } 245243791Sdim mutex_unlock(&clnt_fd_lock); 246243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 247243791Sdim if (!__rpc_fd2sockinfo(fd, &si)) 248243791Sdim goto err; 249243791Sdim 250243791Sdim ct->ct_closeit = FALSE; 251243791Sdim 252243791Sdim /* 253243791Sdim * Set up private data struct 254243791Sdim */ 255243791Sdim ct->ct_fd = fd; 256243791Sdim ct->ct_wait.tv_usec = 0; 257243791Sdim ct->ct_waitset = FALSE; 258243791Sdim ct->ct_addr.buf = malloc(raddr->maxlen); 259243791Sdim if (ct->ct_addr.buf == NULL) 260243791Sdim goto err; 261243791Sdim memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); 262243791Sdim ct->ct_addr.len = raddr->maxlen; 263243791Sdim ct->ct_addr.maxlen = raddr->maxlen; 264243791Sdim 265243791Sdim /* 266243791Sdim * Initialize call message 267243791Sdim */ 268243791Sdim (void)gettimeofday(&now, NULL); 269243791Sdim call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); 270263509Sdim call_msg.rm_direction = CALL; 271243791Sdim call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 272243791Sdim call_msg.rm_call.cb_prog = (u_int32_t)prog; 273243791Sdim call_msg.rm_call.cb_vers = (u_int32_t)vers; 274243791Sdim 275243791Sdim /* 276243791Sdim * pre-serialize the static part of the call msg and stash it away 277243791Sdim */ 278243791Sdim xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 279243791Sdim XDR_ENCODE); 280243791Sdim if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 281243791Sdim if (ct->ct_closeit) { 282243791Sdim (void)_close(fd); 283243791Sdim } 284243791Sdim goto err; 285243791Sdim } 286243791Sdim ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 287243791Sdim XDR_DESTROY(&(ct->ct_xdrs)); 288263509Sdim assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); 289243791Sdim 290243791Sdim /* 291243791Sdim * Create a client handle which uses xdrrec for serialization 292243791Sdim * and authnone for authentication. 293243791Sdim */ 294243791Sdim cl->cl_ops = clnt_vc_ops(); 295243791Sdim cl->cl_private = ct; 296243791Sdim cl->cl_auth = authnone_create(); 297243791Sdim sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 298243791Sdim recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 299243791Sdim xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 300243791Sdim cl->cl_private, read_vc, write_vc); 301243791Sdim return (cl); 302243791Sdim 303243791Sdimerr: 304243791Sdim if (ct) { 305243791Sdim if (ct->ct_addr.len) 306243791Sdim mem_free(ct->ct_addr.buf, ct->ct_addr.len); 307243791Sdim mem_free(ct, sizeof (struct ct_data)); 308243791Sdim } 309243791Sdim if (cl) 310243791Sdim mem_free(cl, sizeof (CLIENT)); 311243791Sdim return ((CLIENT *)NULL); 312243791Sdim} 313243791Sdim 314243791Sdimstatic enum clnt_stat 315243791Sdimclnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 316243791Sdim CLIENT *cl; 317243791Sdim rpcproc_t proc; 318243791Sdim xdrproc_t xdr_args; 319243791Sdim void *args_ptr; 320243791Sdim xdrproc_t xdr_results; 321243791Sdim void *results_ptr; 322243791Sdim struct timeval timeout; 323243791Sdim{ 324243791Sdim struct ct_data *ct = (struct ct_data *) cl->cl_private; 325243791Sdim XDR *xdrs = &(ct->ct_xdrs); 326243791Sdim struct rpc_msg reply_msg; 327243791Sdim u_int32_t x_id; 328243791Sdim u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ 329243791Sdim bool_t shipnow; 330243791Sdim int refreshes = 2; 331243791Sdim sigset_t mask, newmask; 332243791Sdim int rpc_lock_value; 333243791Sdim bool_t reply_stat; 334243791Sdim 335243791Sdim assert(cl != NULL); 336243791Sdim 337243791Sdim sigfillset(&newmask); 338243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 339243791Sdim mutex_lock(&clnt_fd_lock); 340243791Sdim while (vc_fd_locks[ct->ct_fd]) 341243791Sdim cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 342243791Sdim if (__isthreaded) 343243791Sdim rpc_lock_value = 1; 344243791Sdim else 345243791Sdim rpc_lock_value = 0; 346243791Sdim vc_fd_locks[ct->ct_fd] = rpc_lock_value; 347243791Sdim mutex_unlock(&clnt_fd_lock); 348243791Sdim if (!ct->ct_waitset) { 349243791Sdim /* If time is not within limits, we ignore it. */ 350243791Sdim if (time_not_ok(&timeout) == FALSE) 351243791Sdim ct->ct_wait = timeout; 352243791Sdim } 353243791Sdim 354243791Sdim shipnow = 355243791Sdim (xdr_results == NULL && timeout.tv_sec == 0 356243791Sdim && timeout.tv_usec == 0) ? FALSE : TRUE; 357243791Sdim 358243791Sdimcall_again: 359243791Sdim xdrs->x_op = XDR_ENCODE; 360243791Sdim ct->ct_error.re_status = RPC_SUCCESS; 361243791Sdim x_id = ntohl(--(*msg_x_id)); 362243791Sdim 363243791Sdim if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 364243791Sdim if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 365243791Sdim (! XDR_PUTINT32(xdrs, &proc)) || 366243791Sdim (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 367243791Sdim (! (*xdr_args)(xdrs, args_ptr))) { 368243791Sdim if (ct->ct_error.re_status == RPC_SUCCESS) 369243791Sdim ct->ct_error.re_status = RPC_CANTENCODEARGS; 370243791Sdim (void)xdrrec_endofrecord(xdrs, TRUE); 371243791Sdim release_fd_lock(ct->ct_fd, mask); 372243791Sdim return (ct->ct_error.re_status); 373243791Sdim } 374243791Sdim } else { 375243791Sdim *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); 376243791Sdim if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, 377243791Sdim ct->ct_mpos + sizeof(uint32_t), 378243791Sdim xdrs, xdr_args, args_ptr)) { 379243791Sdim if (ct->ct_error.re_status == RPC_SUCCESS) 380263509Sdim ct->ct_error.re_status = RPC_CANTENCODEARGS; 381243791Sdim (void)xdrrec_endofrecord(xdrs, TRUE); 382243791Sdim release_fd_lock(ct->ct_fd, mask); 383243791Sdim return (ct->ct_error.re_status); 384243791Sdim } 385243791Sdim } 386243791Sdim if (! xdrrec_endofrecord(xdrs, shipnow)) { 387243791Sdim release_fd_lock(ct->ct_fd, mask); 388243791Sdim return (ct->ct_error.re_status = RPC_CANTSEND); 389243791Sdim } 390243791Sdim if (! shipnow) { 391243791Sdim release_fd_lock(ct->ct_fd, mask); 392243791Sdim return (RPC_SUCCESS); 393243791Sdim } 394243791Sdim /* 395243791Sdim * Hack to provide rpc-based message passing 396243791Sdim */ 397243791Sdim if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 398263509Sdim release_fd_lock(ct->ct_fd, mask); 399243791Sdim return(ct->ct_error.re_status = RPC_TIMEDOUT); 400243791Sdim } 401243791Sdim 402243791Sdim 403243791Sdim /* 404243791Sdim * Keep receiving until we get a valid transaction id 405243791Sdim */ 406243791Sdim xdrs->x_op = XDR_DECODE; 407243791Sdim while (TRUE) { 408243791Sdim reply_msg.acpted_rply.ar_verf = _null_auth; 409243791Sdim reply_msg.acpted_rply.ar_results.where = NULL; 410243791Sdim reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 411263509Sdim if (! xdrrec_skiprecord(xdrs)) { 412263509Sdim release_fd_lock(ct->ct_fd, mask); 413243791Sdim return (ct->ct_error.re_status); 414243791Sdim } 415243791Sdim /* now decode and validate the response header */ 416243791Sdim if (! xdr_replymsg(xdrs, &reply_msg)) { 417243791Sdim if (ct->ct_error.re_status == RPC_SUCCESS) 418243791Sdim continue; 419243791Sdim release_fd_lock(ct->ct_fd, mask); 420243791Sdim return (ct->ct_error.re_status); 421243791Sdim } 422243791Sdim if (reply_msg.rm_xid == x_id) 423243791Sdim break; 424243791Sdim } 425243791Sdim 426243791Sdim /* 427243791Sdim * process header 428243791Sdim */ 429243791Sdim _seterr_reply(&reply_msg, &(ct->ct_error)); 430243791Sdim if (ct->ct_error.re_status == RPC_SUCCESS) { 431243791Sdim if (! AUTH_VALIDATE(cl->cl_auth, 432243791Sdim &reply_msg.acpted_rply.ar_verf)) { 433243791Sdim ct->ct_error.re_status = RPC_AUTHERROR; 434243791Sdim ct->ct_error.re_why = AUTH_INVALIDRESP; 435243791Sdim } else { 436243791Sdim if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 437243791Sdim reply_stat = (*xdr_results)(xdrs, results_ptr); 438243791Sdim } else { 439243791Sdim reply_stat = __rpc_gss_unwrap(cl->cl_auth, 440243791Sdim xdrs, xdr_results, results_ptr); 441243791Sdim } 442243791Sdim if (! reply_stat) { 443243791Sdim if (ct->ct_error.re_status == RPC_SUCCESS) 444243791Sdim ct->ct_error.re_status = 445243791Sdim RPC_CANTDECODERES; 446243791Sdim } 447243791Sdim } 448243791Sdim /* free verifier ... */ 449243791Sdim if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 450243791Sdim xdrs->x_op = XDR_FREE; 451243791Sdim (void)xdr_opaque_auth(xdrs, 452243791Sdim &(reply_msg.acpted_rply.ar_verf)); 453243791Sdim } 454243791Sdim } /* end successful completion */ 455243791Sdim else { 456243791Sdim /* maybe our credentials need to be refreshed ... */ 457243791Sdim if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) 458243791Sdim goto call_again; 459243791Sdim } /* end of unsuccessful completion */ 460243791Sdim release_fd_lock(ct->ct_fd, mask); 461243791Sdim return (ct->ct_error.re_status); 462243791Sdim} 463243791Sdim 464243791Sdimstatic void 465243791Sdimclnt_vc_geterr(cl, errp) 466243791Sdim CLIENT *cl; 467243791Sdim struct rpc_err *errp; 468243791Sdim{ 469243791Sdim struct ct_data *ct; 470243791Sdim 471243791Sdim assert(cl != NULL); 472243791Sdim assert(errp != NULL); 473243791Sdim 474243791Sdim ct = (struct ct_data *) cl->cl_private; 475243791Sdim *errp = ct->ct_error; 476243791Sdim} 477243791Sdim 478243791Sdimstatic bool_t 479243791Sdimclnt_vc_freeres(cl, xdr_res, res_ptr) 480243791Sdim CLIENT *cl; 481243791Sdim xdrproc_t xdr_res; 482243791Sdim void *res_ptr; 483243791Sdim{ 484243791Sdim struct ct_data *ct; 485243791Sdim XDR *xdrs; 486243791Sdim bool_t dummy; 487243791Sdim sigset_t mask; 488252723Sdim sigset_t newmask; 489243791Sdim 490243791Sdim assert(cl != NULL); 491243791Sdim 492243791Sdim ct = (struct ct_data *)cl->cl_private; 493243791Sdim xdrs = &(ct->ct_xdrs); 494252723Sdim 495243791Sdim sigfillset(&newmask); 496243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 497243791Sdim mutex_lock(&clnt_fd_lock); 498243791Sdim while (vc_fd_locks[ct->ct_fd]) 499243791Sdim cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 500243791Sdim xdrs->x_op = XDR_FREE; 501243791Sdim dummy = (*xdr_res)(xdrs, res_ptr); 502243791Sdim mutex_unlock(&clnt_fd_lock); 503243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 504243791Sdim cond_signal(&vc_cv[ct->ct_fd]); 505243791Sdim 506243791Sdim return dummy; 507243791Sdim} 508243791Sdim 509243791Sdim/*ARGSUSED*/ 510243791Sdimstatic void 511243791Sdimclnt_vc_abort(cl) 512243791Sdim CLIENT *cl; 513243791Sdim{ 514243791Sdim} 515243791Sdim 516243791Sdimstatic bool_t 517243791Sdimclnt_vc_control(cl, request, info) 518243791Sdim CLIENT *cl; 519243791Sdim u_int request; 520243791Sdim void *info; 521243791Sdim{ 522243791Sdim struct ct_data *ct; 523243791Sdim void *infop = info; 524243791Sdim sigset_t mask; 525243791Sdim sigset_t newmask; 526243791Sdim int rpc_lock_value; 527243791Sdim 528243791Sdim assert(cl != NULL); 529243791Sdim 530243791Sdim ct = (struct ct_data *)cl->cl_private; 531243791Sdim 532243791Sdim sigfillset(&newmask); 533243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 534243791Sdim mutex_lock(&clnt_fd_lock); 535243791Sdim while (vc_fd_locks[ct->ct_fd]) 536243791Sdim cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 537243791Sdim if (__isthreaded) 538243791Sdim rpc_lock_value = 1; 539243791Sdim else 540243791Sdim rpc_lock_value = 0; 541243791Sdim vc_fd_locks[ct->ct_fd] = rpc_lock_value; 542243791Sdim mutex_unlock(&clnt_fd_lock); 543243791Sdim 544243791Sdim switch (request) { 545243791Sdim case CLSET_FD_CLOSE: 546243791Sdim ct->ct_closeit = TRUE; 547243791Sdim release_fd_lock(ct->ct_fd, mask); 548243791Sdim return (TRUE); 549243791Sdim case CLSET_FD_NCLOSE: 550243791Sdim ct->ct_closeit = FALSE; 551243791Sdim release_fd_lock(ct->ct_fd, mask); 552243791Sdim return (TRUE); 553243791Sdim default: 554243791Sdim break; 555243791Sdim } 556243791Sdim 557243791Sdim /* for other requests which use info */ 558243791Sdim if (info == NULL) { 559243791Sdim release_fd_lock(ct->ct_fd, mask); 560243791Sdim return (FALSE); 561243791Sdim } 562243791Sdim switch (request) { 563243791Sdim case CLSET_TIMEOUT: 564243791Sdim if (time_not_ok((struct timeval *)info)) { 565243791Sdim release_fd_lock(ct->ct_fd, mask); 566243791Sdim return (FALSE); 567243791Sdim } 568243791Sdim ct->ct_wait = *(struct timeval *)infop; 569243791Sdim ct->ct_waitset = TRUE; 570243791Sdim break; 571243791Sdim case CLGET_TIMEOUT: 572243791Sdim *(struct timeval *)infop = ct->ct_wait; 573243791Sdim break; 574243791Sdim case CLGET_SERVER_ADDR: 575243791Sdim (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 576243791Sdim break; 577243791Sdim case CLGET_FD: 578243791Sdim *(int *)info = ct->ct_fd; 579243791Sdim break; 580243791Sdim case CLGET_SVC_ADDR: 581243791Sdim /* The caller should not free this memory area */ 582243791Sdim *(struct netbuf *)info = ct->ct_addr; 583243791Sdim break; 584243791Sdim case CLSET_SVC_ADDR: /* set to new address */ 585243791Sdim release_fd_lock(ct->ct_fd, mask); 586243791Sdim return (FALSE); 587243791Sdim case CLGET_XID: 588243791Sdim /* 589243791Sdim * use the knowledge that xid is the 590243791Sdim * first element in the call structure 591243791Sdim * This will get the xid of the PREVIOUS call 592243791Sdim */ 593243791Sdim *(u_int32_t *)info = 594243791Sdim ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 595243791Sdim break; 596243791Sdim case CLSET_XID: 597243791Sdim /* This will set the xid of the NEXT call */ 598243791Sdim *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 599243791Sdim htonl(*((u_int32_t *)info) + 1); 600243791Sdim /* increment by 1 as clnt_vc_call() decrements once */ 601243791Sdim break; 602243791Sdim case CLGET_VERS: 603243791Sdim /* 604243791Sdim * This RELIES on the information that, in the call body, 605243791Sdim * the version number field is the fifth field from the 606243791Sdim * begining of the RPC header. MUST be changed if the 607243791Sdim * call_struct is changed 608243791Sdim */ 609243791Sdim *(u_int32_t *)info = 610243791Sdim ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 611243791Sdim 4 * BYTES_PER_XDR_UNIT)); 612243791Sdim break; 613243791Sdim 614243791Sdim case CLSET_VERS: 615243791Sdim *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 616243791Sdim 4 * BYTES_PER_XDR_UNIT) = 617243791Sdim htonl(*(u_int32_t *)info); 618243791Sdim break; 619243791Sdim 620243791Sdim case CLGET_PROG: 621243791Sdim /* 622243791Sdim * This RELIES on the information that, in the call body, 623243791Sdim * the program number field is the fourth field from the 624243791Sdim * begining of the RPC header. MUST be changed if the 625243791Sdim * call_struct is changed 626263509Sdim */ 627243791Sdim *(u_int32_t *)info = 628243791Sdim ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 629243791Sdim 3 * BYTES_PER_XDR_UNIT)); 630243791Sdim break; 631243791Sdim 632243791Sdim case CLSET_PROG: 633243791Sdim *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 634243791Sdim 3 * BYTES_PER_XDR_UNIT) = 635243791Sdim htonl(*(u_int32_t *)info); 636243791Sdim break; 637243791Sdim 638243791Sdim default: 639243791Sdim release_fd_lock(ct->ct_fd, mask); 640243791Sdim return (FALSE); 641243791Sdim } 642243791Sdim release_fd_lock(ct->ct_fd, mask); 643243791Sdim return (TRUE); 644243791Sdim} 645243791Sdim 646243791Sdim 647243791Sdimstatic void 648243791Sdimclnt_vc_destroy(cl) 649243791Sdim CLIENT *cl; 650243791Sdim{ 651243791Sdim struct ct_data *ct = (struct ct_data *) cl->cl_private; 652243791Sdim int ct_fd = ct->ct_fd; 653243791Sdim sigset_t mask; 654243791Sdim sigset_t newmask; 655243791Sdim 656243791Sdim assert(cl != NULL); 657243791Sdim 658243791Sdim ct = (struct ct_data *) cl->cl_private; 659243791Sdim 660243791Sdim sigfillset(&newmask); 661243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 662243791Sdim mutex_lock(&clnt_fd_lock); 663243791Sdim while (vc_fd_locks[ct_fd]) 664243791Sdim cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 665243791Sdim if (ct->ct_closeit && ct->ct_fd != -1) { 666243791Sdim (void)_close(ct->ct_fd); 667243791Sdim } 668243791Sdim XDR_DESTROY(&(ct->ct_xdrs)); 669243791Sdim if (ct->ct_addr.buf) 670243791Sdim free(ct->ct_addr.buf); 671243791Sdim mem_free(ct, sizeof(struct ct_data)); 672243791Sdim if (cl->cl_netid && cl->cl_netid[0]) 673243791Sdim mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 674243791Sdim if (cl->cl_tp && cl->cl_tp[0]) 675243791Sdim mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 676243791Sdim mem_free(cl, sizeof(CLIENT)); 677243791Sdim mutex_unlock(&clnt_fd_lock); 678243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 679243791Sdim cond_signal(&vc_cv[ct_fd]); 680243791Sdim} 681243791Sdim 682243791Sdim/* 683243791Sdim * Interface between xdr serializer and tcp connection. 684243791Sdim * Behaves like the system calls, read & write, but keeps some error state 685243791Sdim * around for the rpc level. 686243791Sdim */ 687243791Sdimstatic int 688243791Sdimread_vc(ctp, buf, len) 689243791Sdim void *ctp; 690243791Sdim void *buf; 691243791Sdim int len; 692243791Sdim{ 693243791Sdim struct sockaddr sa; 694243791Sdim socklen_t sal; 695243791Sdim struct ct_data *ct = (struct ct_data *)ctp; 696243791Sdim struct pollfd fd; 697243791Sdim int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + 698243791Sdim (ct->ct_wait.tv_usec / 1000)); 699243791Sdim 700243791Sdim if (len == 0) 701243791Sdim return (0); 702243791Sdim fd.fd = ct->ct_fd; 703243791Sdim fd.events = POLLIN; 704243791Sdim for (;;) { 705243791Sdim switch (_poll(&fd, 1, milliseconds)) { 706243791Sdim case 0: 707243791Sdim ct->ct_error.re_status = RPC_TIMEDOUT; 708243791Sdim return (-1); 709243791Sdim 710243791Sdim case -1: 711243791Sdim if (errno == EINTR) 712243791Sdim continue; 713243791Sdim ct->ct_error.re_status = RPC_CANTRECV; 714243791Sdim ct->ct_error.re_errno = errno; 715243791Sdim return (-1); 716243791Sdim } 717243791Sdim break; 718243791Sdim } 719243791Sdim 720243791Sdim sal = sizeof(sa); 721243791Sdim if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 722243791Sdim (sa.sa_family == AF_LOCAL)) { 723243791Sdim len = __msgread(ct->ct_fd, buf, (size_t)len); 724263509Sdim } else { 725243791Sdim len = _read(ct->ct_fd, buf, (size_t)len); 726243791Sdim } 727243791Sdim 728243791Sdim switch (len) { 729243791Sdim case 0: 730243791Sdim /* premature eof */ 731243791Sdim ct->ct_error.re_errno = ECONNRESET; 732243791Sdim ct->ct_error.re_status = RPC_CANTRECV; 733243791Sdim len = -1; /* it's really an error */ 734243791Sdim break; 735243791Sdim 736243791Sdim case -1: 737243791Sdim ct->ct_error.re_errno = errno; 738243791Sdim ct->ct_error.re_status = RPC_CANTRECV; 739243791Sdim break; 740243791Sdim } 741243791Sdim return (len); 742243791Sdim} 743243791Sdim 744243791Sdimstatic int 745243791Sdimwrite_vc(ctp, buf, len) 746243791Sdim void *ctp; 747243791Sdim void *buf; 748243791Sdim int len; 749243791Sdim{ 750243791Sdim struct sockaddr sa; 751243791Sdim socklen_t sal; 752243791Sdim struct ct_data *ct = (struct ct_data *)ctp; 753243791Sdim int i, cnt; 754243791Sdim 755243791Sdim sal = sizeof(sa); 756243791Sdim if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 757243791Sdim (sa.sa_family == AF_LOCAL)) { 758243791Sdim for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 759243791Sdim if ((i = __msgwrite(ct->ct_fd, buf, 760243791Sdim (size_t)cnt)) == -1) { 761243791Sdim ct->ct_error.re_errno = errno; 762243791Sdim ct->ct_error.re_status = RPC_CANTSEND; 763243791Sdim return (-1); 764243791Sdim } 765243791Sdim } 766243791Sdim } else { 767243791Sdim for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 768243791Sdim if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { 769243791Sdim ct->ct_error.re_errno = errno; 770243791Sdim ct->ct_error.re_status = RPC_CANTSEND; 771243791Sdim return (-1); 772243791Sdim } 773243791Sdim } 774243791Sdim } 775243791Sdim return (len); 776243791Sdim} 777243791Sdim 778243791Sdimstatic struct clnt_ops * 779243791Sdimclnt_vc_ops() 780243791Sdim{ 781243791Sdim static struct clnt_ops ops; 782243791Sdim sigset_t mask, newmask; 783243791Sdim 784243791Sdim /* VARIABLES PROTECTED BY ops_lock: ops */ 785243791Sdim 786243791Sdim sigfillset(&newmask); 787243791Sdim thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 788243791Sdim mutex_lock(&ops_lock); 789243791Sdim if (ops.cl_call == NULL) { 790243791Sdim ops.cl_call = clnt_vc_call; 791243791Sdim ops.cl_abort = clnt_vc_abort; 792243791Sdim ops.cl_geterr = clnt_vc_geterr; 793243791Sdim ops.cl_freeres = clnt_vc_freeres; 794243791Sdim ops.cl_destroy = clnt_vc_destroy; 795243791Sdim ops.cl_control = clnt_vc_control; 796243791Sdim } 797243791Sdim mutex_unlock(&ops_lock); 798243791Sdim thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 799243791Sdim return (&ops); 800243791Sdim} 801243791Sdim 802243791Sdim/* 803243791Sdim * Make sure that the time is not garbage. -1 value is disallowed. 804243791Sdim * Note this is different from time_not_ok in clnt_dg.c 805243791Sdim */ 806243791Sdimstatic bool_t 807243791Sdimtime_not_ok(t) 808243791Sdim struct timeval *t; 809243791Sdim{ 810243791Sdim return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 811243791Sdim t->tv_usec <= -1 || t->tv_usec > 1000000); 812243791Sdim} 813243791Sdim 814243791Sdimstatic int 815243791Sdim__msgread(sock, buf, cnt) 816243791Sdim int sock; 817243791Sdim void *buf; 818243791Sdim size_t cnt; 819243791Sdim{ 820243791Sdim struct iovec iov[1]; 821243791Sdim struct msghdr msg; 822243791Sdim union { 823243791Sdim struct cmsghdr cmsg; 824243791Sdim char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 825243791Sdim } cm; 826243791Sdim 827243791Sdim bzero((char *)&cm, sizeof(cm)); 828243791Sdim iov[0].iov_base = buf; 829243791Sdim iov[0].iov_len = cnt; 830243791Sdim 831243791Sdim msg.msg_iov = iov; 832243791Sdim msg.msg_iovlen = 1; 833243791Sdim msg.msg_name = NULL; 834243791Sdim msg.msg_namelen = 0; 835243791Sdim msg.msg_control = (caddr_t)&cm; 836243791Sdim msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 837243791Sdim msg.msg_flags = 0; 838243791Sdim 839243791Sdim return(_recvmsg(sock, &msg, 0)); 840243791Sdim} 841243791Sdim 842243791Sdimstatic int 843243791Sdim__msgwrite(sock, buf, cnt) 844243791Sdim int sock; 845243791Sdim void *buf; 846243791Sdim size_t cnt; 847243791Sdim{ 848243791Sdim struct iovec iov[1]; 849243791Sdim struct msghdr msg; 850243791Sdim union { 851243791Sdim struct cmsghdr cmsg; 852243791Sdim char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 853243791Sdim } cm; 854243791Sdim 855243791Sdim bzero((char *)&cm, sizeof(cm)); 856243791Sdim iov[0].iov_base = buf; 857243791Sdim iov[0].iov_len = cnt; 858243791Sdim 859243791Sdim cm.cmsg.cmsg_type = SCM_CREDS; 860243791Sdim cm.cmsg.cmsg_level = SOL_SOCKET; 861243791Sdim cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 862243791Sdim 863243791Sdim msg.msg_iov = iov; 864243791Sdim msg.msg_iovlen = 1; 865243791Sdim msg.msg_name = NULL; 866243791Sdim msg.msg_namelen = 0; 867243791Sdim msg.msg_control = (caddr_t)&cm; 868243791Sdim msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 869243791Sdim msg.msg_flags = 0; 870243791Sdim 871243791Sdim return(_sendmsg(sock, &msg, 0)); 872243791Sdim} 873243791Sdim