1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include "opt_kgssapi.h" 38 39 #include <fs/nfs/nfsport.h> 40 41 #include <rpc/rpc.h> 42 #include <rpc/rpcsec_gss.h> 43 #include <rpc/replay.h> 44 45 46 NFSDLOCKMUTEX; 47 48 SVCPOOL *nfscbd_pool; 49 50 static int nfs_cbproc(struct nfsrv_descript *, u_int32_t); 51 52 extern u_long sb_max_adj; 53 extern int nfs_numnfscbd; 54 55 /* 56 * NFS client system calls for handling callbacks. 57 */ 58 59 /* 60 * Handles server to client callbacks. 61 */ 62 static void 63 nfscb_program(struct svc_req *rqst, SVCXPRT *xprt) 64 { 65 struct nfsrv_descript nd; 66 int cacherep, credflavor; 67 68 memset(&nd, 0, sizeof(nd)); 69 if (rqst->rq_proc != NFSPROC_NULL && 70 rqst->rq_proc != NFSV4PROC_CBCOMPOUND) { 71 svcerr_noproc(rqst); 72 svc_freereq(rqst); 73 return; 74 } 75 nd.nd_procnum = rqst->rq_proc; 76 nd.nd_flag = (ND_NFSCB | ND_NFSV4); 77 78 /* 79 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - 80 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP 81 * mounts. 82 */ 83 nd.nd_mrep = rqst->rq_args; 84 rqst->rq_args = NULL; 85 newnfs_realign(&nd.nd_mrep); 86 nd.nd_md = nd.nd_mrep; 87 nd.nd_dpos = mtod(nd.nd_md, caddr_t); 88 nd.nd_nam = svc_getrpccaller(rqst); 89 nd.nd_nam2 = rqst->rq_addr; 90 nd.nd_mreq = NULL; 91 nd.nd_cred = NULL; 92 93 if (nd.nd_procnum != NFSPROC_NULL) { 94 if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) { 95 svcerr_weakauth(rqst); 96 svc_freereq(rqst); 97 m_freem(nd.nd_mrep); 98 return; 99 } 100 101 /* For now, I don't care what credential flavor was used. */ 102 #ifdef notyet 103 #ifdef MAC 104 mac_cred_associate_nfsd(nd.nd_cred); 105 #endif 106 #endif 107 cacherep = nfs_cbproc(&nd, rqst->rq_xid); 108 } else { 109 NFSMGET(nd.nd_mreq); 110 nd.nd_mreq->m_len = 0; 111 cacherep = RC_REPLY; 112 } 113 if (nd.nd_mrep != NULL) 114 m_freem(nd.nd_mrep); 115 116 if (nd.nd_cred != NULL) 117 crfree(nd.nd_cred); 118 119 if (cacherep == RC_DROPIT) { 120 if (nd.nd_mreq != NULL) 121 m_freem(nd.nd_mreq); 122 svc_freereq(rqst); 123 return; 124 } 125 126 if (nd.nd_mreq == NULL) { 127 svcerr_decode(rqst); 128 svc_freereq(rqst); 129 return; 130 } 131 132 if (nd.nd_repstat & NFSERR_AUTHERR) { 133 svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); 134 if (nd.nd_mreq != NULL) 135 m_freem(nd.nd_mreq); 136 } else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) { 137 svcerr_systemerr(rqst); 138 } 139 svc_freereq(rqst); 140 } 141 142 /* 143 * Check the cache and, optionally, do the RPC. 144 * Return the appropriate cache response. 145 */ 146 static int 147 nfs_cbproc(struct nfsrv_descript *nd, u_int32_t xid) 148 { 149 struct thread *td = curthread; 150 int cacherep; 151 152 if (nd->nd_nam2 == NULL) 153 nd->nd_flag |= ND_STREAMSOCK; 154 155 nfscl_docb(nd, td); 156 if (nd->nd_repstat == NFSERR_DONTREPLY) 157 cacherep = RC_DROPIT; 158 else 159 cacherep = RC_REPLY; 160 return (cacherep); 161 } 162 163 /* 164 * Adds a socket to the list for servicing by nfscbds. 165 */ 166 int 167 nfscbd_addsock(struct file *fp) 168 { 169 int siz; 170 struct socket *so; 171 int error; 172 SVCXPRT *xprt; 173 174 so = fp->f_data; 175 176 siz = sb_max_adj; 177 error = soreserve(so, siz, siz); 178 if (error) 179 return (error); 180 181 /* 182 * Steal the socket from userland so that it doesn't close 183 * unexpectedly. 184 */ 185 if (so->so_type == SOCK_DGRAM) 186 xprt = svc_dg_create(nfscbd_pool, so, 0, 0); 187 else 188 xprt = svc_vc_create(nfscbd_pool, so, 0, 0); 189 if (xprt) { 190 fp->f_ops = &badfileops; 191 fp->f_data = NULL; 192 svc_reg(xprt, NFS_CALLBCKPROG, NFSV4_CBVERS, nfscb_program, 193 NULL); 194 SVC_RELEASE(xprt); 195 } 196 197 return (0); 198 } 199 200 /* 201 * Called by nfssvc() for nfscbds. Just loops around servicing rpc requests 202 * until it is killed by a signal. 203 * 204 * For now, only support callbacks via RPCSEC_GSS if there is a KerberosV 205 * keytab entry with a host based entry in it on the client. (I'm not even 206 * sure that getting Acceptor credentials for a user principal with a 207 * credentials cache is possible, but even if it is, major changes to the 208 * kgssapi would be required.) 209 * I don't believe that this is a serious limitation since, as of 2009, most 210 * NFSv4 servers supporting callbacks are using AUTH_SYS for callbacks even 211 * when the client is using RPCSEC_GSS. (This BSD server uses AUTH_SYS 212 * for callbacks unless nfsrv_gsscallbackson is set non-zero.) 213 */ 214 int 215 nfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args) 216 { 217 char principal[128]; 218 int error; 219 220 if (args != NULL) { 221 error = copyinstr(args->principal, principal, 222 sizeof(principal), NULL); 223 if (error) 224 return (error); 225 } else { 226 principal[0] = '\0'; 227 } 228 229 /* 230 * Only the first nfsd actually does any work. The RPC code 231 * adds threads to it as needed. Any extra processes offered 232 * by nfsd just exit. If nfsd is new enough, it will call us 233 * once with a structure that specifies how many threads to 234 * use. 235 */ 236 NFSD_LOCK(); 237 if (nfs_numnfscbd == 0) { 238 nfs_numnfscbd++; 239 240 NFSD_UNLOCK(); 241 242 if (principal[0] != '\0') 243 rpc_gss_set_svc_name_call(principal, "kerberosv5", 244 GSS_C_INDEFINITE, NFS_CALLBCKPROG, NFSV4_CBVERS); 245 246 nfscbd_pool->sp_minthreads = 4; 247 nfscbd_pool->sp_maxthreads = 4; 248 249 svc_run(nfscbd_pool); 250 251 rpc_gss_clear_svc_name_call(NFS_CALLBCKPROG, NFSV4_CBVERS); 252 253 NFSD_LOCK(); 254 nfs_numnfscbd--; 255 nfsrvd_cbinit(1); 256 } 257 NFSD_UNLOCK(); 258 259 return (0); 260 } 261 262 /* 263 * Initialize the data structures for the server. 264 * Handshake with any new nfsds starting up to avoid any chance of 265 * corruption. 266 */ 267 void 268 nfsrvd_cbinit(int terminating) 269 { 270 271 NFSD_LOCK_ASSERT(); 272 273 if (terminating) { 274 NFSD_UNLOCK(); 275 svcpool_destroy(nfscbd_pool); 276 nfscbd_pool = NULL; 277 NFSD_LOCK(); 278 } 279 280 NFSD_UNLOCK(); 281 282 nfscbd_pool = svcpool_create("nfscbd", NULL); 283 nfscbd_pool->sp_rcache = NULL; 284 nfscbd_pool->sp_assign = NULL; 285 nfscbd_pool->sp_done = NULL; 286 287 NFSD_LOCK(); 288 } 289 290