nfs_clkrpc.c revision 223309
1145516Sdarrenr/*- 2145516Sdarrenr * Copyright (c) 1989, 1993 3145516Sdarrenr * The Regents of the University of California. All rights reserved. 4145516Sdarrenr * 5145516Sdarrenr * This code is derived from software contributed to Berkeley by 6145516Sdarrenr * Rick Macklem at The University of Guelph. 7145516Sdarrenr * 8145516Sdarrenr * Redistribution and use in source and binary forms, with or without 9145516Sdarrenr * modification, are permitted provided that the following conditions 10145516Sdarrenr * are met: 11145516Sdarrenr * 1. Redistributions of source code must retain the above copyright 12145516Sdarrenr * notice, this list of conditions and the following disclaimer. 13145516Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright 14145516Sdarrenr * notice, this list of conditions and the following disclaimer in the 15145516Sdarrenr * documentation and/or other materials provided with the distribution. 16145516Sdarrenr * 4. Neither the name of the University nor the names of its contributors 17145516Sdarrenr * may be used to endorse or promote products derived from this software 18145516Sdarrenr * without specific prior written permission. 19145516Sdarrenr * 20145516Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21145516Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22145516Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23145516Sdarrenr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24145516Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25145516Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26145516Sdarrenr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27145516Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28145516Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29145516Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30145516Sdarrenr * SUCH DAMAGE. 31145516Sdarrenr * 32145516Sdarrenr */ 33145516Sdarrenr 34145516Sdarrenr#include <sys/cdefs.h> 35145516Sdarrenr__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clkrpc.c 223309 2011-06-19 22:08:55Z rmacklem $"); 36145516Sdarrenr 37145516Sdarrenr#include "opt_inet6.h" 38145516Sdarrenr#include "opt_kgssapi.h" 39145516Sdarrenr 40145516Sdarrenr#include <fs/nfs/nfsport.h> 41145516Sdarrenr 42145516Sdarrenr#include <rpc/rpc.h> 43145516Sdarrenr#include <rpc/rpcsec_gss.h> 44145516Sdarrenr#include <rpc/replay.h> 45145516Sdarrenr 46145516Sdarrenr 47145516SdarrenrNFSDLOCKMUTEX; 48145516Sdarrenr 49145516SdarrenrSVCPOOL *nfscbd_pool; 50145516Sdarrenr 51145516Sdarrenrstatic int nfs_cbproc(struct nfsrv_descript *, u_int32_t); 52145516Sdarrenr 53145516Sdarrenrextern u_long sb_max_adj; 54145516Sdarrenrextern int nfs_numnfscbd; 55145516Sdarrenr 56170268Sdarrenr/* 57145516Sdarrenr * NFS client system calls for handling callbacks. 58145516Sdarrenr */ 59145516Sdarrenr 60145516Sdarrenr/* 61145516Sdarrenr * Handles server to client callbacks. 62145516Sdarrenr */ 63145516Sdarrenrstatic void 64145516Sdarrenrnfscb_program(struct svc_req *rqst, SVCXPRT *xprt) 65145516Sdarrenr{ 66145516Sdarrenr struct nfsrv_descript nd; 67145516Sdarrenr int cacherep, credflavor; 68145516Sdarrenr 69145516Sdarrenr memset(&nd, 0, sizeof(nd)); 70145516Sdarrenr if (rqst->rq_proc != NFSPROC_NULL && 71145516Sdarrenr rqst->rq_proc != NFSV4PROC_CBCOMPOUND) { 72145516Sdarrenr svcerr_noproc(rqst); 73145516Sdarrenr svc_freereq(rqst); 74145516Sdarrenr return; 75145516Sdarrenr } 76145516Sdarrenr nd.nd_procnum = rqst->rq_proc; 77145516Sdarrenr nd.nd_flag = (ND_NFSCB | ND_NFSV4); 78145516Sdarrenr 79145516Sdarrenr /* 80145516Sdarrenr * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - 81145516Sdarrenr * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP 82145516Sdarrenr * mounts. 83145516Sdarrenr */ 84145516Sdarrenr nd.nd_mrep = rqst->rq_args; 85145516Sdarrenr rqst->rq_args = NULL; 86145516Sdarrenr newnfs_realign(&nd.nd_mrep); 87145516Sdarrenr nd.nd_md = nd.nd_mrep; 88145516Sdarrenr nd.nd_dpos = mtod(nd.nd_md, caddr_t); 89145516Sdarrenr nd.nd_nam = svc_getrpccaller(rqst); 90145516Sdarrenr nd.nd_nam2 = rqst->rq_addr; 91145516Sdarrenr nd.nd_mreq = NULL; 92145516Sdarrenr nd.nd_cred = NULL; 93145516Sdarrenr 94145516Sdarrenr if (nd.nd_procnum != NFSPROC_NULL) { 95145516Sdarrenr if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) { 96145516Sdarrenr svcerr_weakauth(rqst); 97145516Sdarrenr svc_freereq(rqst); 98145516Sdarrenr m_freem(nd.nd_mrep); 99145516Sdarrenr return; 100145516Sdarrenr } 101145516Sdarrenr 102145516Sdarrenr /* For now, I don't care what credential flavor was used. */ 103145516Sdarrenr#ifdef notyet 104145516Sdarrenr#ifdef MAC 105145516Sdarrenr mac_cred_associate_nfsd(nd.nd_cred); 106170268Sdarrenr#endif 107170268Sdarrenr#endif 108170268Sdarrenr cacherep = nfs_cbproc(&nd, rqst->rq_xid); 109170268Sdarrenr } else { 110170268Sdarrenr NFSMGET(nd.nd_mreq); 111170268Sdarrenr nd.nd_mreq->m_len = 0; 112147547Sdarrenr cacherep = RC_REPLY; 113170268Sdarrenr } 114170268Sdarrenr if (nd.nd_mrep != NULL) 115170268Sdarrenr m_freem(nd.nd_mrep); 116170268Sdarrenr 117170268Sdarrenr if (nd.nd_cred != NULL) 118170268Sdarrenr crfree(nd.nd_cred); 119170268Sdarrenr 120170268Sdarrenr if (cacherep == RC_DROPIT) { 121170268Sdarrenr if (nd.nd_mreq != NULL) 122170268Sdarrenr m_freem(nd.nd_mreq); 123170268Sdarrenr svc_freereq(rqst); 124170268Sdarrenr return; 125170268Sdarrenr } 126147547Sdarrenr 127145516Sdarrenr if (nd.nd_mreq == NULL) { 128145516Sdarrenr svcerr_decode(rqst); 129170268Sdarrenr svc_freereq(rqst); 130170268Sdarrenr return; 131170268Sdarrenr } 132145516Sdarrenr 133145516Sdarrenr if (nd.nd_repstat & NFSERR_AUTHERR) { 134145516Sdarrenr svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); 135170268Sdarrenr if (nd.nd_mreq != NULL) 136145516Sdarrenr m_freem(nd.nd_mreq); 137145516Sdarrenr } else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) { 138145516Sdarrenr svcerr_systemerr(rqst); 139145516Sdarrenr } 140145516Sdarrenr svc_freereq(rqst); 141145516Sdarrenr} 142145516Sdarrenr 143145516Sdarrenr/* 144145516Sdarrenr * Check the cache and, optionally, do the RPC. 145145516Sdarrenr * Return the appropriate cache response. 146145516Sdarrenr */ 147145516Sdarrenrstatic int 148145516Sdarrenrnfs_cbproc(struct nfsrv_descript *nd, u_int32_t xid) 149145516Sdarrenr{ 150153876Sguido struct thread *td = curthread; 151145516Sdarrenr int cacherep; 152153876Sguido 153145516Sdarrenr if (nd->nd_nam2 == NULL) 154145516Sdarrenr nd->nd_flag |= ND_STREAMSOCK; 155145516Sdarrenr 156170268Sdarrenr nfscl_docb(nd, td); 157170268Sdarrenr if (nd->nd_repstat == NFSERR_DONTREPLY) 158170268Sdarrenr cacherep = RC_DROPIT; 159170268Sdarrenr else 160170268Sdarrenr cacherep = RC_REPLY; 161170268Sdarrenr return (cacherep); 162170268Sdarrenr} 163170268Sdarrenr 164170268Sdarrenr/* 165170268Sdarrenr * Adds a socket to the list for servicing by nfscbds. 166145516Sdarrenr */ 167170268Sdarrenrint 168170268Sdarrenrnfscbd_addsock(struct file *fp) 169170268Sdarrenr{ 170170268Sdarrenr int siz; 171145516Sdarrenr struct socket *so; 172170268Sdarrenr int error; 173170268Sdarrenr SVCXPRT *xprt; 174170268Sdarrenr 175170268Sdarrenr so = fp->f_data; 176170268Sdarrenr 177170268Sdarrenr siz = sb_max_adj; 178145516Sdarrenr error = soreserve(so, siz, siz); 179170268Sdarrenr if (error) 180170268Sdarrenr return (error); 181145516Sdarrenr 182170268Sdarrenr /* 183170268Sdarrenr * Steal the socket from userland so that it doesn't close 184145516Sdarrenr * unexpectedly. 185145516Sdarrenr */ 186145516Sdarrenr if (so->so_type == SOCK_DGRAM) 187145516Sdarrenr xprt = svc_dg_create(nfscbd_pool, so, 0, 0); 188145516Sdarrenr else 189145516Sdarrenr xprt = svc_vc_create(nfscbd_pool, so, 0, 0); 190170268Sdarrenr if (xprt) { 191170268Sdarrenr fp->f_ops = &badfileops; 192170268Sdarrenr fp->f_data = NULL; 193145516Sdarrenr svc_reg(xprt, NFS_CALLBCKPROG, NFSV4_CBVERS, nfscb_program, 194145516Sdarrenr NULL); 195145516Sdarrenr SVC_RELEASE(xprt); 196170268Sdarrenr } 197145516Sdarrenr 198145516Sdarrenr return (0); 199145516Sdarrenr} 200170268Sdarrenr 201145516Sdarrenr/* 202145516Sdarrenr * Called by nfssvc() for nfscbds. Just loops around servicing rpc requests 203145516Sdarrenr * until it is killed by a signal. 204145516Sdarrenr * 205170268Sdarrenr * For now, only support callbacks via RPCSEC_GSS if there is a KerberosV 206170268Sdarrenr * keytab entry with a host based entry in it on the client. (I'm not even 207170268Sdarrenr * sure that getting Acceptor credentials for a user principal with a 208145516Sdarrenr * credentials cache is possible, but even if it is, major changes to the 209145516Sdarrenr * kgssapi would be required.) 210145516Sdarrenr * I don't believe that this is a serious limitation since, as of 2009, most 211145516Sdarrenr * NFSv4 servers supporting callbacks are using AUTH_SYS for callbacks even 212145516Sdarrenr * when the client is using RPCSEC_GSS. (This BSD server uses AUTH_SYS 213145516Sdarrenr * for callbacks unless nfsrv_gsscallbackson is set non-zero.) 214145516Sdarrenr */ 215145516Sdarrenrint 216170268Sdarrenrnfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args) 217145516Sdarrenr{ 218145516Sdarrenr char principal[128]; 219145516Sdarrenr int error; 220145516Sdarrenr 221170268Sdarrenr if (args != NULL) { 222170268Sdarrenr error = copyinstr(args->principal, principal, 223170268Sdarrenr sizeof(principal), NULL); 224170268Sdarrenr if (error) 225170268Sdarrenr return (error); 226145516Sdarrenr } else { 227170268Sdarrenr principal[0] = '\0'; 228170268Sdarrenr } 229170268Sdarrenr 230170268Sdarrenr /* 231170268Sdarrenr * Only the first nfsd actually does any work. The RPC code 232170268Sdarrenr * adds threads to it as needed. Any extra processes offered 233170268Sdarrenr * by nfsd just exit. If nfsd is new enough, it will call us 234170268Sdarrenr * once with a structure that specifies how many threads to 235170268Sdarrenr * use. 236170268Sdarrenr */ 237145516Sdarrenr NFSD_LOCK(); 238145516Sdarrenr if (nfs_numnfscbd == 0) { 239145516Sdarrenr nfs_numnfscbd++; 240145516Sdarrenr 241145516Sdarrenr NFSD_UNLOCK(); 242170268Sdarrenr 243170268Sdarrenr if (principal[0] != '\0') 244170268Sdarrenr rpc_gss_set_svc_name_call(principal, "kerberosv5", 245170268Sdarrenr GSS_C_INDEFINITE, NFS_CALLBCKPROG, NFSV4_CBVERS); 246170268Sdarrenr 247170268Sdarrenr nfscbd_pool->sp_minthreads = 4; 248170268Sdarrenr nfscbd_pool->sp_maxthreads = 4; 249170268Sdarrenr 250170268Sdarrenr svc_run(nfscbd_pool); 251170268Sdarrenr 252170268Sdarrenr rpc_gss_clear_svc_name_call(NFS_CALLBCKPROG, NFSV4_CBVERS); 253170268Sdarrenr 254170268Sdarrenr NFSD_LOCK(); 255170268Sdarrenr nfs_numnfscbd--; 256170268Sdarrenr nfsrvd_cbinit(1); 257170268Sdarrenr } 258170268Sdarrenr NFSD_UNLOCK(); 259170268Sdarrenr 260170268Sdarrenr return (0); 261170268Sdarrenr} 262170268Sdarrenr 263170268Sdarrenr/* 264170268Sdarrenr * Initialize the data structures for the server. 265170268Sdarrenr * Handshake with any new nfsds starting up to avoid any chance of 266170268Sdarrenr * corruption. 267170268Sdarrenr */ 268170268Sdarrenrvoid 269170268Sdarrenrnfsrvd_cbinit(int terminating) 270170268Sdarrenr{ 271170268Sdarrenr 272170268Sdarrenr NFSD_LOCK_ASSERT(); 273170268Sdarrenr 274170268Sdarrenr if (terminating) { 275170268Sdarrenr NFSD_UNLOCK(); 276170268Sdarrenr svcpool_destroy(nfscbd_pool); 277170268Sdarrenr nfscbd_pool = NULL; 278170268Sdarrenr NFSD_LOCK(); 279170268Sdarrenr } 280170268Sdarrenr 281170268Sdarrenr NFSD_UNLOCK(); 282170268Sdarrenr 283170268Sdarrenr nfscbd_pool = svcpool_create("nfscbd", NULL); 284170268Sdarrenr nfscbd_pool->sp_rcache = NULL; 285170268Sdarrenr nfscbd_pool->sp_assign = NULL; 286170268Sdarrenr nfscbd_pool->sp_done = NULL; 287170268Sdarrenr 288170268Sdarrenr NFSD_LOCK(); 289145516Sdarrenr} 290145516Sdarrenr 291145516Sdarrenr