174462Salfred/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 274462Salfred 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6261046Smav * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 1774462Salfred * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 2974462Salfred */ 3074462Salfred 3174462Salfred#if defined(LIBC_SCCS) && !defined(lint) 32136581Sobrienstatic char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 3374462Salfredstatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34136581Sobrienstatic char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 3574462Salfred#endif 3692990Sobrien#include <sys/cdefs.h> 3792990Sobrien__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/clnt_vc.c 309498 2016-12-03 18:40:39Z ngie $"); 3874462Salfred 3974462Salfred/* 4074462Salfred * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 4174462Salfred * 4274462Salfred * Copyright (C) 1984, Sun Microsystems, Inc. 4374462Salfred * 4474462Salfred * TCP based RPC supports 'batched calls'. 4574462Salfred * A sequence of calls may be batched-up in a send buffer. The rpc call 4674462Salfred * return immediately to the client even though the call was not necessarily 4774462Salfred * sent. The batching occurs if the results' xdr routine is NULL (0) AND 4874462Salfred * the rpc timeout value is zero (see clnt.h, rpc). 4974462Salfred * 5074462Salfred * Clients should NOT casually batch calls that in fact return results; that is, 5174462Salfred * the server side should be aware that a call is batched and not produce any 5274462Salfred * return message. Batched calls that produce many result messages can 5374462Salfred * deadlock (netlock) the client and the server.... 5474462Salfred * 5574462Salfred * Now go hang yourself. 5674462Salfred */ 5774462Salfred 5875094Siedowse#include "namespace.h" 5974462Salfred#include "reentrant.h" 6074462Salfred#include <sys/types.h> 6174462Salfred#include <sys/poll.h> 6274462Salfred#include <sys/syslog.h> 6374462Salfred#include <sys/socket.h> 6474462Salfred#include <sys/un.h> 6574462Salfred#include <sys/uio.h> 6674462Salfred 6790868Smike#include <arpa/inet.h> 6874462Salfred#include <assert.h> 6974462Salfred#include <err.h> 7074462Salfred#include <errno.h> 7174462Salfred#include <netdb.h> 7274462Salfred#include <stdio.h> 7374462Salfred#include <stdlib.h> 7474462Salfred#include <string.h> 7574462Salfred#include <unistd.h> 7674462Salfred#include <signal.h> 7774462Salfred 7874462Salfred#include <rpc/rpc.h> 79181344Sdfr#include <rpc/rpcsec_gss.h> 8074462Salfred#include "un-namespace.h" 8174462Salfred#include "rpc_com.h" 82156090Sdeischen#include "mt_misc.h" 8374462Salfred 8474462Salfred#define MCALL_MSG_SIZE 24 8574462Salfred 8674660Salfredstruct cmessage { 8774660Salfred struct cmsghdr cmsg; 8874660Salfred struct cmsgcred cmcred; 8974660Salfred}; 9074660Salfred 9195658Sdesstatic enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 9295658Sdes xdrproc_t, void *, struct timeval); 9392905Sobrienstatic void clnt_vc_geterr(CLIENT *, struct rpc_err *); 9495658Sdesstatic bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); 9592905Sobrienstatic void clnt_vc_abort(CLIENT *); 9699996Salfredstatic bool_t clnt_vc_control(CLIENT *, u_int, void *); 9792905Sobrienstatic void clnt_vc_destroy(CLIENT *); 9892905Sobrienstatic struct clnt_ops *clnt_vc_ops(void); 9992905Sobrienstatic bool_t time_not_ok(struct timeval *); 10095658Sdesstatic int read_vc(void *, void *, int); 10195658Sdesstatic int write_vc(void *, void *, int); 10274462Salfredstatic int __msgwrite(int, void *, size_t); 10374462Salfredstatic int __msgread(int, void *, size_t); 10474462Salfred 10574462Salfredstruct ct_data { 10674462Salfred int ct_fd; /* connection's fd */ 10774462Salfred bool_t ct_closeit; /* close it on destroy */ 10874462Salfred struct timeval ct_wait; /* wait interval in milliseconds */ 10974462Salfred bool_t ct_waitset; /* wait set by clnt_control? */ 11074462Salfred struct netbuf ct_addr; /* remote addr */ 11174462Salfred struct rpc_err ct_error; 11274462Salfred union { 11374462Salfred char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 11474462Salfred u_int32_t ct_mcalli; 11574462Salfred } ct_u; 11674462Salfred u_int ct_mpos; /* pos after marshal */ 11774462Salfred XDR ct_xdrs; /* XDR stream */ 11874462Salfred}; 11974462Salfred 12074462Salfred/* 12174462Salfred * This machinery implements per-fd locks for MT-safety. It is not 12274462Salfred * sufficient to do per-CLIENT handle locks for MT-safety because a 12374462Salfred * user may create more than one CLIENT handle with the same fd behind 12474462Salfred * it. Therfore, we allocate an array of flags (vc_fd_locks), protected 12574462Salfred * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables 12674462Salfred * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some 12774462Salfred * CLIENT handle created for that fd. 12874462Salfred * The current implementation holds locks across the entire RPC and reply. 12974462Salfred * Yes, this is silly, and as soon as this code is proven to work, this 13074462Salfred * should be the first thing fixed. One step at a time. 13174462Salfred */ 13274462Salfredstatic int *vc_fd_locks; 13374462Salfredstatic cond_t *vc_cv; 13474462Salfred#define release_fd_lock(fd, mask) { \ 13574462Salfred mutex_lock(&clnt_fd_lock); \ 13675144Siedowse vc_fd_locks[fd] = 0; \ 13774462Salfred mutex_unlock(&clnt_fd_lock); \ 13874462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 13974462Salfred cond_signal(&vc_cv[fd]); \ 14074462Salfred} 14174462Salfred 14274462Salfredstatic const char clnt_vc_errstr[] = "%s : %s"; 14374462Salfredstatic const char clnt_vc_str[] = "clnt_vc_create"; 14474462Salfredstatic const char clnt_read_vc_str[] = "read_vc"; 14574462Salfredstatic const char __no_mem_str[] = "out of memory"; 14674462Salfred 14774462Salfred/* 14874462Salfred * Create a client handle for a connection. 14974462Salfred * Default options are set, which the user can change using clnt_control()'s. 15074462Salfred * The rpc/vc package does buffering similar to stdio, so the client 15174462Salfred * must pick send and receive buffer sizes, 0 => use the default. 15274462Salfred * NB: fd is copied into a private area. 15374462Salfred * NB: The rpch->cl_auth is set null authentication. Caller may wish to 15474462Salfred * set this something more useful. 15574462Salfred * 15674462Salfred * fd should be an open socket 157309487Sngie * 158309487Sngie * fd - open file descriptor 159309487Sngie * raddr - servers address 160309487Sngie * prog - program number 161309487Sngie * vers - version number 162309487Sngie * sendsz - buffer send size 163309487Sngie * recvsz - buffer recv size 16474462Salfred */ 16574462SalfredCLIENT * 166309487Sngieclnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog, 167309487Sngie const rpcvers_t vers, u_int sendsz, u_int recvsz) 16874462Salfred{ 16974462Salfred CLIENT *cl; /* client handle */ 17074462Salfred struct ct_data *ct = NULL; /* client handle */ 17174462Salfred struct timeval now; 17274462Salfred struct rpc_msg call_msg; 17374462Salfred static u_int32_t disrupt; 17474462Salfred sigset_t mask; 17574462Salfred sigset_t newmask; 17674462Salfred struct sockaddr_storage ss; 17774462Salfred socklen_t slen; 17874462Salfred struct __rpc_sockinfo si; 17974462Salfred 18074462Salfred if (disrupt == 0) 18174462Salfred disrupt = (u_int32_t)(long)raddr; 18274462Salfred 18374462Salfred cl = (CLIENT *)mem_alloc(sizeof (*cl)); 18474462Salfred ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 18574462Salfred if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { 18674462Salfred (void) syslog(LOG_ERR, clnt_vc_errstr, 18774462Salfred clnt_vc_str, __no_mem_str); 18874462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 18974462Salfred rpc_createerr.cf_error.re_errno = errno; 19074462Salfred goto err; 19174462Salfred } 19274462Salfred ct->ct_addr.buf = NULL; 19374462Salfred sigfillset(&newmask); 19474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 19574462Salfred mutex_lock(&clnt_fd_lock); 19674462Salfred if (vc_fd_locks == (int *) NULL) { 19774462Salfred int cv_allocsz, fd_allocsz; 19874462Salfred int dtbsize = __rpc_dtbsize(); 19974462Salfred 20074462Salfred fd_allocsz = dtbsize * sizeof (int); 20174462Salfred vc_fd_locks = (int *) mem_alloc(fd_allocsz); 20274462Salfred if (vc_fd_locks == (int *) NULL) { 20374462Salfred mutex_unlock(&clnt_fd_lock); 20474462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 20574462Salfred goto err; 20674462Salfred } else 20774462Salfred memset(vc_fd_locks, '\0', fd_allocsz); 20874462Salfred 20974462Salfred assert(vc_cv == (cond_t *) NULL); 21074462Salfred cv_allocsz = dtbsize * sizeof (cond_t); 21174462Salfred vc_cv = (cond_t *) mem_alloc(cv_allocsz); 21274462Salfred if (vc_cv == (cond_t *) NULL) { 21374462Salfred mem_free(vc_fd_locks, fd_allocsz); 21474462Salfred vc_fd_locks = (int *) NULL; 21574462Salfred mutex_unlock(&clnt_fd_lock); 21674462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 21774462Salfred goto err; 21874462Salfred } else { 21974462Salfred int i; 22074462Salfred 22174462Salfred for (i = 0; i < dtbsize; i++) 22274462Salfred cond_init(&vc_cv[i], 0, (void *) 0); 22374462Salfred } 22474462Salfred } else 22574462Salfred assert(vc_cv != (cond_t *) NULL); 22674462Salfred 22774462Salfred /* 22874462Salfred * XXX - fvdl connecting while holding a mutex? 22974462Salfred */ 23074462Salfred slen = sizeof ss; 23174462Salfred if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 23274462Salfred if (errno != ENOTCONN) { 23374462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 23474462Salfred rpc_createerr.cf_error.re_errno = errno; 23574462Salfred mutex_unlock(&clnt_fd_lock); 23675097Siedowse thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 23774462Salfred goto err; 23874462Salfred } 23974462Salfred if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 24074462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 24174462Salfred rpc_createerr.cf_error.re_errno = errno; 24274462Salfred mutex_unlock(&clnt_fd_lock); 24375097Siedowse thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 24474462Salfred goto err; 24574462Salfred } 24674462Salfred } 24774462Salfred mutex_unlock(&clnt_fd_lock); 248162190Smbr thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 24974462Salfred if (!__rpc_fd2sockinfo(fd, &si)) 25074462Salfred goto err; 25174462Salfred 25274462Salfred ct->ct_closeit = FALSE; 25374462Salfred 25474462Salfred /* 25574462Salfred * Set up private data struct 25674462Salfred */ 25774462Salfred ct->ct_fd = fd; 25874462Salfred ct->ct_wait.tv_usec = 0; 25974462Salfred ct->ct_waitset = FALSE; 26074462Salfred ct->ct_addr.buf = malloc(raddr->maxlen); 26174462Salfred if (ct->ct_addr.buf == NULL) 26274462Salfred goto err; 26377588Siedowse memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); 264247550Skevlo ct->ct_addr.len = raddr->len; 26574462Salfred ct->ct_addr.maxlen = raddr->maxlen; 26674462Salfred 26774462Salfred /* 26874462Salfred * Initialize call message 26974462Salfred */ 27074462Salfred (void)gettimeofday(&now, NULL); 27174462Salfred call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); 27274462Salfred call_msg.rm_direction = CALL; 27374462Salfred call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 27474462Salfred call_msg.rm_call.cb_prog = (u_int32_t)prog; 27574462Salfred call_msg.rm_call.cb_vers = (u_int32_t)vers; 27674462Salfred 27774462Salfred /* 27874462Salfred * pre-serialize the static part of the call msg and stash it away 27974462Salfred */ 28074462Salfred xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 28174462Salfred XDR_ENCODE); 28274462Salfred if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 28374462Salfred if (ct->ct_closeit) { 28474462Salfred (void)_close(fd); 28574462Salfred } 28674462Salfred goto err; 28774462Salfred } 28874462Salfred ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 28974462Salfred XDR_DESTROY(&(ct->ct_xdrs)); 290181344Sdfr assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); 29174462Salfred 29274462Salfred /* 29374462Salfred * Create a client handle which uses xdrrec for serialization 29474462Salfred * and authnone for authentication. 29574462Salfred */ 29674462Salfred cl->cl_ops = clnt_vc_ops(); 29774462Salfred cl->cl_private = ct; 29874462Salfred cl->cl_auth = authnone_create(); 29974462Salfred sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 30074462Salfred recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 30174462Salfred xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 30274462Salfred cl->cl_private, read_vc, write_vc); 30374462Salfred return (cl); 30474462Salfred 30574462Salfrederr: 306266243Sbrueffer if (ct) { 307266243Sbrueffer if (ct->ct_addr.len) 308266243Sbrueffer mem_free(ct->ct_addr.buf, ct->ct_addr.len); 309266243Sbrueffer mem_free(ct, sizeof (struct ct_data)); 31074462Salfred } 311266243Sbrueffer if (cl) 312266243Sbrueffer mem_free(cl, sizeof (CLIENT)); 31374462Salfred return ((CLIENT *)NULL); 31474462Salfred} 31574462Salfred 31674462Salfredstatic enum clnt_stat 317309487Sngieclnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr, 318309487Sngie xdrproc_t xdr_results, void *results_ptr, struct timeval timeout) 31974462Salfred{ 32074462Salfred struct ct_data *ct = (struct ct_data *) cl->cl_private; 32174462Salfred XDR *xdrs = &(ct->ct_xdrs); 32274462Salfred struct rpc_msg reply_msg; 32374462Salfred u_int32_t x_id; 32474462Salfred u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ 32574462Salfred bool_t shipnow; 32674462Salfred int refreshes = 2; 32774462Salfred sigset_t mask, newmask; 32874462Salfred int rpc_lock_value; 329181344Sdfr bool_t reply_stat; 33074462Salfred 33174462Salfred assert(cl != NULL); 33274462Salfred 33374462Salfred sigfillset(&newmask); 33474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 33574462Salfred mutex_lock(&clnt_fd_lock); 33674462Salfred while (vc_fd_locks[ct->ct_fd]) 33774462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 33874462Salfred if (__isthreaded) 33974462Salfred rpc_lock_value = 1; 34074462Salfred else 34174462Salfred rpc_lock_value = 0; 34274462Salfred vc_fd_locks[ct->ct_fd] = rpc_lock_value; 34374462Salfred mutex_unlock(&clnt_fd_lock); 34474462Salfred if (!ct->ct_waitset) { 34574462Salfred /* If time is not within limits, we ignore it. */ 34674462Salfred if (time_not_ok(&timeout) == FALSE) 34774462Salfred ct->ct_wait = timeout; 34874462Salfred } 34974462Salfred 35074462Salfred shipnow = 35174462Salfred (xdr_results == NULL && timeout.tv_sec == 0 35274462Salfred && timeout.tv_usec == 0) ? FALSE : TRUE; 35374462Salfred 35474462Salfredcall_again: 35574462Salfred xdrs->x_op = XDR_ENCODE; 35674462Salfred ct->ct_error.re_status = RPC_SUCCESS; 35774462Salfred x_id = ntohl(--(*msg_x_id)); 35874462Salfred 359181344Sdfr if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 360181344Sdfr if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 361181344Sdfr (! XDR_PUTINT32(xdrs, &proc)) || 362181344Sdfr (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 363181344Sdfr (! (*xdr_args)(xdrs, args_ptr))) { 364181344Sdfr if (ct->ct_error.re_status == RPC_SUCCESS) 365181344Sdfr ct->ct_error.re_status = RPC_CANTENCODEARGS; 366181344Sdfr (void)xdrrec_endofrecord(xdrs, TRUE); 367181344Sdfr release_fd_lock(ct->ct_fd, mask); 368181344Sdfr return (ct->ct_error.re_status); 369181344Sdfr } 370181344Sdfr } else { 371181344Sdfr *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); 372181344Sdfr if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, 373181344Sdfr ct->ct_mpos + sizeof(uint32_t), 374181344Sdfr xdrs, xdr_args, args_ptr)) { 375181344Sdfr if (ct->ct_error.re_status == RPC_SUCCESS) 376181344Sdfr ct->ct_error.re_status = RPC_CANTENCODEARGS; 377181344Sdfr (void)xdrrec_endofrecord(xdrs, TRUE); 378181344Sdfr release_fd_lock(ct->ct_fd, mask); 379181344Sdfr return (ct->ct_error.re_status); 380181344Sdfr } 38174462Salfred } 38274462Salfred if (! xdrrec_endofrecord(xdrs, shipnow)) { 38374462Salfred release_fd_lock(ct->ct_fd, mask); 38474462Salfred return (ct->ct_error.re_status = RPC_CANTSEND); 38574462Salfred } 38674462Salfred if (! shipnow) { 38774462Salfred release_fd_lock(ct->ct_fd, mask); 38874462Salfred return (RPC_SUCCESS); 38974462Salfred } 39074462Salfred /* 39174462Salfred * Hack to provide rpc-based message passing 39274462Salfred */ 39374462Salfred if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 39474462Salfred release_fd_lock(ct->ct_fd, mask); 39574462Salfred return(ct->ct_error.re_status = RPC_TIMEDOUT); 39674462Salfred } 39774462Salfred 39874462Salfred 39974462Salfred /* 40074462Salfred * Keep receiving until we get a valid transaction id 40174462Salfred */ 40274462Salfred xdrs->x_op = XDR_DECODE; 40374462Salfred while (TRUE) { 40474462Salfred reply_msg.acpted_rply.ar_verf = _null_auth; 40574462Salfred reply_msg.acpted_rply.ar_results.where = NULL; 40674462Salfred reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 40774462Salfred if (! xdrrec_skiprecord(xdrs)) { 40874462Salfred release_fd_lock(ct->ct_fd, mask); 40974462Salfred return (ct->ct_error.re_status); 41074462Salfred } 41174462Salfred /* now decode and validate the response header */ 41274462Salfred if (! xdr_replymsg(xdrs, &reply_msg)) { 41374462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) 41474462Salfred continue; 41574462Salfred release_fd_lock(ct->ct_fd, mask); 41674462Salfred return (ct->ct_error.re_status); 41774462Salfred } 41874462Salfred if (reply_msg.rm_xid == x_id) 41974462Salfred break; 42074462Salfred } 42174462Salfred 42274462Salfred /* 42374462Salfred * process header 42474462Salfred */ 42574462Salfred _seterr_reply(&reply_msg, &(ct->ct_error)); 42674462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) { 42774462Salfred if (! AUTH_VALIDATE(cl->cl_auth, 42874462Salfred &reply_msg.acpted_rply.ar_verf)) { 42974462Salfred ct->ct_error.re_status = RPC_AUTHERROR; 43074462Salfred ct->ct_error.re_why = AUTH_INVALIDRESP; 431181344Sdfr } else { 432181344Sdfr if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 433181344Sdfr reply_stat = (*xdr_results)(xdrs, results_ptr); 434181344Sdfr } else { 435181344Sdfr reply_stat = __rpc_gss_unwrap(cl->cl_auth, 436181344Sdfr xdrs, xdr_results, results_ptr); 437181344Sdfr } 438181344Sdfr if (! reply_stat) { 439181344Sdfr if (ct->ct_error.re_status == RPC_SUCCESS) 440181344Sdfr ct->ct_error.re_status = 441181344Sdfr RPC_CANTDECODERES; 442181344Sdfr } 44374462Salfred } 44474462Salfred /* free verifier ... */ 44574462Salfred if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 44674462Salfred xdrs->x_op = XDR_FREE; 44774462Salfred (void)xdr_opaque_auth(xdrs, 44874462Salfred &(reply_msg.acpted_rply.ar_verf)); 44974462Salfred } 45074462Salfred } /* end successful completion */ 45174462Salfred else { 45274462Salfred /* maybe our credentials need to be refreshed ... */ 45374462Salfred if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) 45474462Salfred goto call_again; 45574462Salfred } /* end of unsuccessful completion */ 45674462Salfred release_fd_lock(ct->ct_fd, mask); 45774462Salfred return (ct->ct_error.re_status); 45874462Salfred} 45974462Salfred 46074462Salfredstatic void 461309487Sngieclnt_vc_geterr(CLIENT *cl, struct rpc_err *errp) 46274462Salfred{ 46374462Salfred struct ct_data *ct; 46474462Salfred 46574462Salfred assert(cl != NULL); 46674462Salfred assert(errp != NULL); 46774462Salfred 46874462Salfred ct = (struct ct_data *) cl->cl_private; 46974462Salfred *errp = ct->ct_error; 47074462Salfred} 47174462Salfred 47274462Salfredstatic bool_t 473309487Sngieclnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 47474462Salfred{ 47574462Salfred struct ct_data *ct; 47674462Salfred XDR *xdrs; 47774462Salfred bool_t dummy; 47874462Salfred sigset_t mask; 47974462Salfred sigset_t newmask; 48074462Salfred 48174462Salfred assert(cl != NULL); 48274462Salfred 48374462Salfred ct = (struct ct_data *)cl->cl_private; 48474462Salfred xdrs = &(ct->ct_xdrs); 48574462Salfred 48674462Salfred sigfillset(&newmask); 48774462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 48874462Salfred mutex_lock(&clnt_fd_lock); 48974462Salfred while (vc_fd_locks[ct->ct_fd]) 49074462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 49174462Salfred xdrs->x_op = XDR_FREE; 49274462Salfred dummy = (*xdr_res)(xdrs, res_ptr); 49374462Salfred mutex_unlock(&clnt_fd_lock); 49474462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 49574462Salfred cond_signal(&vc_cv[ct->ct_fd]); 49674462Salfred 49774462Salfred return dummy; 49874462Salfred} 49974462Salfred 50074462Salfred/*ARGSUSED*/ 50174462Salfredstatic void 502309487Sngieclnt_vc_abort(CLIENT *cl) 50374462Salfred{ 50474462Salfred} 50574462Salfred 506309498Sngiestatic __inline void 507309498Sngiehtonlp(void *dst, const void *src, uint32_t incr) 508309498Sngie{ 509309498Sngie /* We are aligned, so we think */ 510309498Sngie *(uint32_t *)dst = htonl(*(const uint32_t *)src + incr); 511309498Sngie} 512309498Sngie 513309498Sngiestatic __inline void 514309498Sngientohlp(void *dst, const void *src) 515309498Sngie{ 516309498Sngie /* We are aligned, so we think */ 517309498Sngie *(uint32_t *)dst = htonl(*(const uint32_t *)src); 518309498Sngie} 519309498Sngie 52074462Salfredstatic bool_t 521309487Sngieclnt_vc_control(CLIENT *cl, u_int request, void *info) 52274462Salfred{ 52374462Salfred struct ct_data *ct; 52474462Salfred void *infop = info; 52574462Salfred sigset_t mask; 52674462Salfred sigset_t newmask; 52774462Salfred int rpc_lock_value; 52874462Salfred 52974462Salfred assert(cl != NULL); 53074462Salfred 53174462Salfred ct = (struct ct_data *)cl->cl_private; 53274462Salfred 53374462Salfred sigfillset(&newmask); 53474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 53574462Salfred mutex_lock(&clnt_fd_lock); 53674462Salfred while (vc_fd_locks[ct->ct_fd]) 53774462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 53874462Salfred if (__isthreaded) 53974462Salfred rpc_lock_value = 1; 54074462Salfred else 54174462Salfred rpc_lock_value = 0; 54274462Salfred vc_fd_locks[ct->ct_fd] = rpc_lock_value; 54374462Salfred mutex_unlock(&clnt_fd_lock); 54474462Salfred 54574462Salfred switch (request) { 54674462Salfred case CLSET_FD_CLOSE: 54774462Salfred ct->ct_closeit = TRUE; 54874462Salfred release_fd_lock(ct->ct_fd, mask); 54974462Salfred return (TRUE); 55074462Salfred case CLSET_FD_NCLOSE: 55174462Salfred ct->ct_closeit = FALSE; 55274462Salfred release_fd_lock(ct->ct_fd, mask); 55374462Salfred return (TRUE); 55474462Salfred default: 55574462Salfred break; 55674462Salfred } 55774462Salfred 55874462Salfred /* for other requests which use info */ 55974462Salfred if (info == NULL) { 56074462Salfred release_fd_lock(ct->ct_fd, mask); 56174462Salfred return (FALSE); 56274462Salfred } 56374462Salfred switch (request) { 56474462Salfred case CLSET_TIMEOUT: 56599996Salfred if (time_not_ok((struct timeval *)info)) { 56674462Salfred release_fd_lock(ct->ct_fd, mask); 56774462Salfred return (FALSE); 56874462Salfred } 56974462Salfred ct->ct_wait = *(struct timeval *)infop; 57074462Salfred ct->ct_waitset = TRUE; 57174462Salfred break; 57274462Salfred case CLGET_TIMEOUT: 57374462Salfred *(struct timeval *)infop = ct->ct_wait; 57474462Salfred break; 57574462Salfred case CLGET_SERVER_ADDR: 57674462Salfred (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 57774462Salfred break; 57874462Salfred case CLGET_FD: 57999996Salfred *(int *)info = ct->ct_fd; 58074462Salfred break; 58174462Salfred case CLGET_SVC_ADDR: 58274462Salfred /* The caller should not free this memory area */ 58399996Salfred *(struct netbuf *)info = ct->ct_addr; 58474462Salfred break; 58574462Salfred case CLSET_SVC_ADDR: /* set to new address */ 58674462Salfred release_fd_lock(ct->ct_fd, mask); 58774462Salfred return (FALSE); 58874462Salfred case CLGET_XID: 58974462Salfred /* 59074462Salfred * use the knowledge that xid is the 59174462Salfred * first element in the call structure 59274462Salfred * This will get the xid of the PREVIOUS call 59374462Salfred */ 594309498Sngie ntohlp(info, &ct->ct_u.ct_mcalli); 59574462Salfred break; 59674462Salfred case CLSET_XID: 59774462Salfred /* This will set the xid of the NEXT call */ 59874462Salfred /* increment by 1 as clnt_vc_call() decrements once */ 599309498Sngie htonlp(&ct->ct_u.ct_mcalli, info, 1); 60074462Salfred break; 60174462Salfred case CLGET_VERS: 60274462Salfred /* 60374462Salfred * This RELIES on the information that, in the call body, 60474462Salfred * the version number field is the fifth field from the 60574462Salfred * begining of the RPC header. MUST be changed if the 60674462Salfred * call_struct is changed 60774462Salfred */ 608309498Sngie ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT); 60974462Salfred break; 61074462Salfred 61174462Salfred case CLSET_VERS: 612309498Sngie htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0); 61374462Salfred break; 61474462Salfred 61574462Salfred case CLGET_PROG: 61674462Salfred /* 61774462Salfred * This RELIES on the information that, in the call body, 61874462Salfred * the program number field is the fourth field from the 61974462Salfred * begining of the RPC header. MUST be changed if the 62074462Salfred * call_struct is changed 62174462Salfred */ 622309498Sngie ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT); 62374462Salfred break; 62474462Salfred 62574462Salfred case CLSET_PROG: 626309498Sngie htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0); 62774462Salfred break; 62874462Salfred 62974462Salfred default: 63074462Salfred release_fd_lock(ct->ct_fd, mask); 63174462Salfred return (FALSE); 63274462Salfred } 63374462Salfred release_fd_lock(ct->ct_fd, mask); 63474462Salfred return (TRUE); 63574462Salfred} 63674462Salfred 63774462Salfred 63874462Salfredstatic void 639309487Sngieclnt_vc_destroy(CLIENT *cl) 64074462Salfred{ 64174462Salfred struct ct_data *ct = (struct ct_data *) cl->cl_private; 64274462Salfred int ct_fd = ct->ct_fd; 64374462Salfred sigset_t mask; 64474462Salfred sigset_t newmask; 64574462Salfred 64674462Salfred assert(cl != NULL); 64774462Salfred 64874462Salfred ct = (struct ct_data *) cl->cl_private; 64974462Salfred 65074462Salfred sigfillset(&newmask); 65174462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 65274462Salfred mutex_lock(&clnt_fd_lock); 65374462Salfred while (vc_fd_locks[ct_fd]) 65474462Salfred cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 65574462Salfred if (ct->ct_closeit && ct->ct_fd != -1) { 65674462Salfred (void)_close(ct->ct_fd); 65774462Salfred } 65874462Salfred XDR_DESTROY(&(ct->ct_xdrs)); 659290899Sngie free(ct->ct_addr.buf); 66074462Salfred mem_free(ct, sizeof(struct ct_data)); 661241143Spfg if (cl->cl_netid && cl->cl_netid[0]) 662241143Spfg mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 663241143Spfg if (cl->cl_tp && cl->cl_tp[0]) 664241143Spfg mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 66574462Salfred mem_free(cl, sizeof(CLIENT)); 66674462Salfred mutex_unlock(&clnt_fd_lock); 66774462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 66874462Salfred cond_signal(&vc_cv[ct_fd]); 66974462Salfred} 67074462Salfred 67174462Salfred/* 67274462Salfred * Interface between xdr serializer and tcp connection. 67374462Salfred * Behaves like the system calls, read & write, but keeps some error state 67474462Salfred * around for the rpc level. 67574462Salfred */ 67674462Salfredstatic int 677309487Sngieread_vc(void *ctp, void *buf, int len) 67874462Salfred{ 67974462Salfred struct sockaddr sa; 68074462Salfred socklen_t sal; 68195658Sdes struct ct_data *ct = (struct ct_data *)ctp; 68274462Salfred struct pollfd fd; 68374462Salfred int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + 68474462Salfred (ct->ct_wait.tv_usec / 1000)); 68574462Salfred 68674462Salfred if (len == 0) 68774462Salfred return (0); 68874462Salfred fd.fd = ct->ct_fd; 68974462Salfred fd.events = POLLIN; 69074462Salfred for (;;) { 69174462Salfred switch (_poll(&fd, 1, milliseconds)) { 69274462Salfred case 0: 69374462Salfred ct->ct_error.re_status = RPC_TIMEDOUT; 69474462Salfred return (-1); 69574462Salfred 69674462Salfred case -1: 69774462Salfred if (errno == EINTR) 69874462Salfred continue; 69974462Salfred ct->ct_error.re_status = RPC_CANTRECV; 70074462Salfred ct->ct_error.re_errno = errno; 70174462Salfred return (-1); 70274462Salfred } 70374462Salfred break; 70474462Salfred } 70574462Salfred 70674462Salfred sal = sizeof(sa); 70774462Salfred if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 70874462Salfred (sa.sa_family == AF_LOCAL)) { 70974462Salfred len = __msgread(ct->ct_fd, buf, (size_t)len); 71074462Salfred } else { 71174462Salfred len = _read(ct->ct_fd, buf, (size_t)len); 71274462Salfred } 71374462Salfred 71474462Salfred switch (len) { 71574462Salfred case 0: 71674462Salfred /* premature eof */ 71774462Salfred ct->ct_error.re_errno = ECONNRESET; 71874462Salfred ct->ct_error.re_status = RPC_CANTRECV; 71974462Salfred len = -1; /* it's really an error */ 72074462Salfred break; 72174462Salfred 72274462Salfred case -1: 72374462Salfred ct->ct_error.re_errno = errno; 72474462Salfred ct->ct_error.re_status = RPC_CANTRECV; 72574462Salfred break; 72674462Salfred } 72774462Salfred return (len); 72874462Salfred} 72974462Salfred 73074462Salfredstatic int 731309487Sngiewrite_vc(void *ctp, void *buf, int len) 73274462Salfred{ 73374462Salfred struct sockaddr sa; 73474462Salfred socklen_t sal; 73595658Sdes struct ct_data *ct = (struct ct_data *)ctp; 73674462Salfred int i, cnt; 73774462Salfred 73874462Salfred sal = sizeof(sa); 73974462Salfred if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 74074462Salfred (sa.sa_family == AF_LOCAL)) { 741143347Sstefanf for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 74274462Salfred if ((i = __msgwrite(ct->ct_fd, buf, 74374462Salfred (size_t)cnt)) == -1) { 74474462Salfred ct->ct_error.re_errno = errno; 74574462Salfred ct->ct_error.re_status = RPC_CANTSEND; 74674462Salfred return (-1); 74774462Salfred } 74874462Salfred } 74974462Salfred } else { 750133693Sstefanf for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 75174462Salfred if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { 75274462Salfred ct->ct_error.re_errno = errno; 75374462Salfred ct->ct_error.re_status = RPC_CANTSEND; 75474462Salfred return (-1); 75574462Salfred } 75674462Salfred } 75774462Salfred } 75874462Salfred return (len); 75974462Salfred} 76074462Salfred 76174462Salfredstatic struct clnt_ops * 762309487Sngieclnt_vc_ops(void) 76374462Salfred{ 76474462Salfred static struct clnt_ops ops; 76574462Salfred sigset_t mask, newmask; 76674462Salfred 76774462Salfred /* VARIABLES PROTECTED BY ops_lock: ops */ 76874462Salfred 76974462Salfred sigfillset(&newmask); 77074462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 77174462Salfred mutex_lock(&ops_lock); 77274462Salfred if (ops.cl_call == NULL) { 77374462Salfred ops.cl_call = clnt_vc_call; 77474462Salfred ops.cl_abort = clnt_vc_abort; 77574462Salfred ops.cl_geterr = clnt_vc_geterr; 77674462Salfred ops.cl_freeres = clnt_vc_freeres; 77774462Salfred ops.cl_destroy = clnt_vc_destroy; 77874462Salfred ops.cl_control = clnt_vc_control; 77974462Salfred } 78074462Salfred mutex_unlock(&ops_lock); 78174462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 78274462Salfred return (&ops); 78374462Salfred} 78474462Salfred 78574462Salfred/* 78674462Salfred * Make sure that the time is not garbage. -1 value is disallowed. 78774462Salfred * Note this is different from time_not_ok in clnt_dg.c 78874462Salfred */ 78974462Salfredstatic bool_t 790309487Sngietime_not_ok(struct timeval *t) 79174462Salfred{ 79274462Salfred return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 79374462Salfred t->tv_usec <= -1 || t->tv_usec > 1000000); 79474462Salfred} 79574462Salfred 79674627Salfredstatic int 797309487Sngie__msgread(int sock, void *buf, size_t cnt) 79874462Salfred{ 79974462Salfred struct iovec iov[1]; 80074462Salfred struct msghdr msg; 80184472Sdwmalone union { 80284472Sdwmalone struct cmsghdr cmsg; 80384472Sdwmalone char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 80484472Sdwmalone } cm; 80574462Salfred 80674462Salfred bzero((char *)&cm, sizeof(cm)); 80774462Salfred iov[0].iov_base = buf; 80874462Salfred iov[0].iov_len = cnt; 80974462Salfred 81074462Salfred msg.msg_iov = iov; 81174462Salfred msg.msg_iovlen = 1; 81274462Salfred msg.msg_name = NULL; 81374462Salfred msg.msg_namelen = 0; 81474462Salfred msg.msg_control = (caddr_t)&cm; 81584472Sdwmalone msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 81674462Salfred msg.msg_flags = 0; 81774462Salfred 81874462Salfred return(_recvmsg(sock, &msg, 0)); 81974462Salfred} 82074627Salfred 82174462Salfredstatic int 822309487Sngie__msgwrite(int sock, void *buf, size_t cnt) 82374462Salfred{ 82474462Salfred struct iovec iov[1]; 82574462Salfred struct msghdr msg; 82684472Sdwmalone union { 82784472Sdwmalone struct cmsghdr cmsg; 82884472Sdwmalone char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 82984472Sdwmalone } cm; 83074462Salfred 83174462Salfred bzero((char *)&cm, sizeof(cm)); 83274462Salfred iov[0].iov_base = buf; 83374462Salfred iov[0].iov_len = cnt; 83474462Salfred 83574462Salfred cm.cmsg.cmsg_type = SCM_CREDS; 83674462Salfred cm.cmsg.cmsg_level = SOL_SOCKET; 83784472Sdwmalone cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 83874462Salfred 83974462Salfred msg.msg_iov = iov; 84074462Salfred msg.msg_iovlen = 1; 84174462Salfred msg.msg_name = NULL; 84274462Salfred msg.msg_namelen = 0; 84374462Salfred msg.msg_control = (caddr_t)&cm; 84484472Sdwmalone msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 84574462Salfred msg.msg_flags = 0; 84674462Salfred 84774462Salfred return(_sendmsg(sock, &msg, 0)); 84874462Salfred} 849