177943Sdfr/*- 277943Sdfr * Copyright (c) 1989, 1993 377943Sdfr * The Regents of the University of California. All rights reserved. 477943Sdfr * 577943Sdfr * This code is derived from software contributed to Berkeley by 677943Sdfr * Rick Macklem at The University of Guelph. 777943Sdfr * 877943Sdfr * Redistribution and use in source and binary forms, with or without 977943Sdfr * modification, are permitted provided that the following conditions 1077943Sdfr * are met: 1177943Sdfr * 1. Redistributions of source code must retain the above copyright 1277943Sdfr * notice, this list of conditions and the following disclaimer. 1377943Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1477943Sdfr * notice, this list of conditions and the following disclaimer in the 1577943Sdfr * documentation and/or other materials provided with the distribution. 1677943Sdfr * 4. Neither the name of the University nor the names of its contributors 1777943Sdfr * may be used to endorse or promote products derived from this software 1877943Sdfr * without specific prior written permission. 1977943Sdfr * 2077943Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2177943Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2277943Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2377943Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2477943Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2577943Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2677943Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2777943Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28113038Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29113038Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3078332Sobrien * SUCH DAMAGE. 3177943Sdfr * 3277943Sdfr */ 3377943Sdfr 3483857Sdfr#include <sys/cdefs.h> 3583904Sdfr__FBSDID("$FreeBSD: stable/10/sys/fs/nfsclient/nfs_clkrpc.c 317524 2017-04-27 21:27:20Z rmacklem $"); 3683904Sdfr 37108025Smarcel#include "opt_kgssapi.h" 3877943Sdfr 3977943Sdfr#include <fs/nfs/nfsport.h> 4077943Sdfr 4177943Sdfr#include <rpc/rpc.h> 42164010Smarcel#include <rpc/rpcsec_gss.h> 4377943Sdfr#include <rpc/replay.h> 44164010Smarcel 45164010Smarcel 46164010SmarcelNFSDLOCKMUTEX; 47164010Smarcel 4877943Sdfrextern SVCPOOL *nfscbd_pool; 4977943Sdfr 5077943Sdfrstatic int nfs_cbproc(struct nfsrv_descript *, u_int32_t); 5177943Sdfr 5277943Sdfrextern u_long sb_max_adj; 53164010Smarcelextern int nfs_numnfscbd; 5477943Sdfrextern int nfscl_debuglevel; 5583904Sdfr 5683904Sdfr/* 57107722Smarcel * NFS client system calls for handling callbacks. 58107722Smarcel */ 59118346Smarcel 60107722Smarcel/* 61107722Smarcel * Handles server to client callbacks. 62107722Smarcel */ 63107722Smarcelstatic void 64107722Smarcelnfscb_program(struct svc_req *rqst, SVCXPRT *xprt) 65107722Smarcel{ 66107722Smarcel struct nfsrv_descript nd; 6783904Sdfr int cacherep, credflavor; 6883904Sdfr 6983904Sdfr memset(&nd, 0, sizeof(nd)); 7083904Sdfr if (rqst->rq_proc != NFSPROC_NULL && 7183904Sdfr rqst->rq_proc != NFSV4PROC_CBCOMPOUND) { 7283904Sdfr svcerr_noproc(rqst); 7383904Sdfr svc_freereq(rqst); 7483904Sdfr return; 7583904Sdfr } 7683904Sdfr nd.nd_procnum = rqst->rq_proc; 77107733Smarcel nd.nd_flag = (ND_NFSCB | ND_NFSV4); 78107733Smarcel 7983904Sdfr /* 8083904Sdfr * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - 8183904Sdfr * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP 8283904Sdfr * mounts. 8383904Sdfr */ 8483904Sdfr nd.nd_mrep = rqst->rq_args; 8583904Sdfr rqst->rq_args = NULL; 8683904Sdfr newnfs_realign(&nd.nd_mrep, M_WAITOK); 8783904Sdfr nd.nd_md = nd.nd_mrep; 8883904Sdfr nd.nd_dpos = mtod(nd.nd_md, caddr_t); 8983904Sdfr nd.nd_nam = svc_getrpccaller(rqst); 9083904Sdfr nd.nd_nam2 = rqst->rq_addr; 9183904Sdfr nd.nd_mreq = NULL; 9283904Sdfr nd.nd_cred = NULL; 9383904Sdfr 9483904Sdfr NFSCL_DEBUG(1, "cbproc=%d\n",nd.nd_procnum); 9583904Sdfr if (nd.nd_procnum != NFSPROC_NULL) { 9683904Sdfr if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) { 9783904Sdfr svcerr_weakauth(rqst); 9883904Sdfr svc_freereq(rqst); 9983904Sdfr m_freem(nd.nd_mrep); 10083904Sdfr return; 10183904Sdfr } 10283904Sdfr 103202552Smarcel /* For now, I don't care what credential flavor was used. */ 104202552Smarcel#ifdef notyet 105202552Smarcel#ifdef MAC 106202552Smarcel mac_cred_associate_nfsd(nd.nd_cred); 107202552Smarcel#endif 108202552Smarcel#endif 109202552Smarcel cacherep = nfs_cbproc(&nd, rqst->rq_xid); 110202552Smarcel } else { 111202552Smarcel NFSMGET(nd.nd_mreq); 112202552Smarcel nd.nd_mreq->m_len = 0; 113202552Smarcel cacherep = RC_REPLY; 114202552Smarcel } 115202552Smarcel if (nd.nd_mrep != NULL) 116202552Smarcel m_freem(nd.nd_mrep); 117202552Smarcel 118202552Smarcel if (nd.nd_cred != NULL) 119202552Smarcel crfree(nd.nd_cred); 120202552Smarcel 121202552Smarcel if (cacherep == RC_DROPIT) { 122202552Smarcel if (nd.nd_mreq != NULL) 123202552Smarcel m_freem(nd.nd_mreq); 124202552Smarcel svc_freereq(rqst); 125202552Smarcel return; 126202552Smarcel } 127202552Smarcel 128202552Smarcel if (nd.nd_mreq == NULL) { 129202552Smarcel svcerr_decode(rqst); 130202552Smarcel svc_freereq(rqst); 131202552Smarcel return; 132202552Smarcel } 133202552Smarcel 134202552Smarcel if (nd.nd_repstat & NFSERR_AUTHERR) { 135202552Smarcel svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); 136202552Smarcel if (nd.nd_mreq != NULL) 137202552Smarcel m_freem(nd.nd_mreq); 138202552Smarcel } else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) 139202552Smarcel svcerr_systemerr(rqst); 14077943Sdfr else 141107723Smarcel NFSCL_DEBUG(1, "cbrep sent\n"); 14277943Sdfr svc_freereq(rqst); 143202552Smarcel} 14493411Smarcel 145202552Smarcel/* 14693411Smarcel * Check the cache and, optionally, do the RPC. 14778332Sobrien * Return the appropriate cache response. 14877943Sdfr */ 14977943Sdfrstatic int 15077943Sdfrnfs_cbproc(struct nfsrv_descript *nd, u_int32_t xid) 15177943Sdfr{ 15277943Sdfr struct thread *td = curthread; 15377943Sdfr int cacherep; 15477943Sdfr 15577943Sdfr if (nd->nd_nam2 == NULL) 156222799Smarcel nd->nd_flag |= ND_STREAMSOCK; 157202552Smarcel 15883904Sdfr nfscl_docb(nd, td); 15983904Sdfr if (nd->nd_repstat == NFSERR_DONTREPLY) 16077943Sdfr cacherep = RC_DROPIT; 16177943Sdfr else 16277943Sdfr cacherep = RC_REPLY; 16377943Sdfr return (cacherep); 16477943Sdfr} 16577943Sdfr 16677943Sdfr/* 167107683Smarcel * Adds a socket to the list for servicing by nfscbds. 168107683Smarcel */ 169107683Smarcelint 170107683Smarcelnfscbd_addsock(struct file *fp) 171107683Smarcel{ 172107683Smarcel int siz; 173107683Smarcel struct socket *so; 174107683Smarcel int error; 175107683Smarcel SVCXPRT *xprt; 176107683Smarcel 17777943Sdfr so = fp->f_data; 178202552Smarcel 179202552Smarcel siz = sb_max_adj; 180202552Smarcel error = soreserve(so, siz, siz); 181202552Smarcel if (error) 182295538Ssmh return (error); 183295538Ssmh 184202552Smarcel /* 185202552Smarcel * Steal the socket from userland so that it doesn't close 186164010Smarcel * unexpectedly. 18778332Sobrien */ 18877943Sdfr if (so->so_type == SOCK_DGRAM) 189202552Smarcel xprt = svc_dg_create(nfscbd_pool, so, 0, 0); 190202552Smarcel else 191202552Smarcel xprt = svc_vc_create(nfscbd_pool, so, 0, 0); 192202552Smarcel if (xprt) { 193202552Smarcel fp->f_ops = &badfileops; 194202552Smarcel fp->f_data = NULL; 19578332Sobrien svc_reg(xprt, NFS_CALLBCKPROG, NFSV4_CBVERS, nfscb_program, 196202552Smarcel NULL); 197164010Smarcel SVC_RELEASE(xprt); 198164010Smarcel } 199164010Smarcel 200220313Smarcel return (0); 201220313Smarcel} 202220313Smarcel 203164010Smarcel/* 20477943Sdfr * Called by nfssvc() for nfscbds. Just loops around servicing rpc requests 20577943Sdfr * until it is killed by a signal. 20677943Sdfr * 20778332Sobrien * For now, only support callbacks via RPCSEC_GSS if there is a KerberosV 20877943Sdfr * keytab entry with a host based entry in it on the client. (I'm not even 20977943Sdfr * sure that getting Acceptor credentials for a user principal with a 21077943Sdfr * credentials cache is possible, but even if it is, major changes to the 21177943Sdfr * kgssapi would be required.) 21277943Sdfr * I don't believe that this is a serious limitation since, as of 2009, most 21377943Sdfr * NFSv4 servers supporting callbacks are using AUTH_SYS for callbacks even 21477943Sdfr * when the client is using RPCSEC_GSS. (This BSD server uses AUTH_SYS 21578332Sobrien * for callbacks unless nfsrv_gsscallbackson is set non-zero.) 216222799Smarcel */ 21778332Sobrienint 21877943Sdfrnfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args) 21983215Sdfr{ 220222799Smarcel char principal[128]; 221222799Smarcel int error; 222222799Smarcel 223222799Smarcel if (args != NULL) { 224222799Smarcel error = copyinstr(args->principal, principal, 225222799Smarcel sizeof(principal), NULL); 226222799Smarcel if (error) 227222799Smarcel return (error); 228222799Smarcel } else { 229222799Smarcel principal[0] = '\0'; 230222799Smarcel } 23183215Sdfr 23283215Sdfr /* 23383215Sdfr * Only the first nfsd actually does any work. The RPC code 23483215Sdfr * adds threads to it as needed. Any extra processes offered 23583215Sdfr * by nfsd just exit. If nfsd is new enough, it will call us 23683215Sdfr * once with a structure that specifies how many threads to 23783215Sdfr * use. 23883215Sdfr */ 23983215Sdfr NFSD_LOCK(); 24083215Sdfr if (nfs_numnfscbd == 0) { 24183215Sdfr nfs_numnfscbd++; 24283215Sdfr 24383215Sdfr NFSD_UNLOCK(); 24483215Sdfr 24583215Sdfr if (principal[0] != '\0') 24683215Sdfr rpc_gss_set_svc_name_call(principal, "kerberosv5", 24783215Sdfr GSS_C_INDEFINITE, NFS_CALLBCKPROG, NFSV4_CBVERS); 24883215Sdfr 24983215Sdfr nfscbd_pool->sp_minthreads = 4; 25083215Sdfr nfscbd_pool->sp_maxthreads = 4; 25183216Sdfr 25283215Sdfr svc_run(nfscbd_pool); 25383215Sdfr 25483215Sdfr rpc_gss_clear_svc_name_call(NFS_CALLBCKPROG, NFSV4_CBVERS); 25583215Sdfr 25683215Sdfr NFSD_LOCK(); 25783215Sdfr nfs_numnfscbd--; 25883215Sdfr nfsrvd_cbinit(1); 25983215Sdfr } 26083215Sdfr NFSD_UNLOCK(); 26183215Sdfr 26283215Sdfr return (0); 26383857Sdfr} 26483215Sdfr 26583215Sdfr/* 26683215Sdfr * Initialize the data structures for the server. 26783215Sdfr * Handshake with any new nfsds starting up to avoid any chance of 26883215Sdfr * corruption. 26983857Sdfr */ 27083215Sdfrvoid 27183215Sdfrnfsrvd_cbinit(int terminating) 27283215Sdfr{ 27383216Sdfr 27483215Sdfr NFSD_LOCK_ASSERT(); 27583215Sdfr 27683215Sdfr if (terminating) { 27783215Sdfr /* Wait for any xprt registrations to complete. */ 27883216Sdfr while (nfs_numnfscbd > 0) 27983215Sdfr msleep(&nfs_numnfscbd, NFSDLOCKMUTEXPTR, PZERO, 28083215Sdfr "nfscbdt", 0); 28183215Sdfr if (nfscbd_pool != NULL) { 28283215Sdfr NFSD_UNLOCK(); 28383215Sdfr svcpool_close(nfscbd_pool); 28483215Sdfr NFSD_LOCK(); 28583215Sdfr } 28683215Sdfr } 28783215Sdfr 28883215Sdfr if (nfscbd_pool == NULL) { 28983215Sdfr NFSD_UNLOCK(); 29083215Sdfr nfscbd_pool = svcpool_create("nfscbd", NULL); 29183215Sdfr nfscbd_pool->sp_rcache = NULL; 29283215Sdfr nfscbd_pool->sp_assign = NULL; 29383215Sdfr nfscbd_pool->sp_done = NULL; 29483215Sdfr NFSD_LOCK(); 29583215Sdfr } 29683215Sdfr} 29783215Sdfr 29883215Sdfr