nfs_nfsdkrpc.c revision 291869
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: stable/10/sys/fs/nfsserver/nfs_nfsdkrpc.c 291869 2015-12-05 21:38:53Z rmacklem $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39 40#include "opt_inet6.h" 41#include "opt_kgssapi.h" 42 43#include <fs/nfs/nfsport.h> 44 45#include <rpc/rpc.h> 46#include <rpc/rpcsec_gss.h> 47 48#include <nfs/nfs_fha.h> 49#include <fs/nfsserver/nfs_fha_new.h> 50 51#include <security/mac/mac_framework.h> 52 53NFSDLOCKMUTEX; 54NFSV4ROOTLOCKMUTEX; 55struct nfsv4lock nfsd_suspend_lock; 56 57/* 58 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 59 */ 60int newnfs_nfsv3_procid[NFS_V3NPROCS] = { 61 NFSPROC_NULL, 62 NFSPROC_GETATTR, 63 NFSPROC_SETATTR, 64 NFSPROC_NOOP, 65 NFSPROC_LOOKUP, 66 NFSPROC_READLINK, 67 NFSPROC_READ, 68 NFSPROC_NOOP, 69 NFSPROC_WRITE, 70 NFSPROC_CREATE, 71 NFSPROC_REMOVE, 72 NFSPROC_RENAME, 73 NFSPROC_LINK, 74 NFSPROC_SYMLINK, 75 NFSPROC_MKDIR, 76 NFSPROC_RMDIR, 77 NFSPROC_READDIR, 78 NFSPROC_FSSTAT, 79 NFSPROC_NOOP, 80 NFSPROC_NOOP, 81 NFSPROC_NOOP, 82 NFSPROC_NOOP, 83}; 84 85 86SYSCTL_DECL(_vfs_nfsd); 87 88SVCPOOL *nfsrvd_pool; 89 90static int nfs_privport = 0; 91SYSCTL_INT(_vfs_nfsd, OID_AUTO, nfs_privport, CTLFLAG_RWTUN, 92 &nfs_privport, 0, 93 "Only allow clients using a privileged port for NFSv2 and 3"); 94 95static int nfs_minvers = NFS_VER2; 96SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_nfsvers, CTLFLAG_RWTUN, 97 &nfs_minvers, 0, "The lowest version of NFS handled by the server"); 98 99static int nfs_maxvers = NFS_VER4; 100SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_nfsvers, CTLFLAG_RWTUN, 101 &nfs_maxvers, 0, "The highest version of NFS handled by the server"); 102 103static int nfs_proc(struct nfsrv_descript *, u_int32_t, SVCXPRT *xprt, 104 struct nfsrvcache **); 105 106extern u_long sb_max_adj; 107extern int newnfs_numnfsd; 108extern struct proc *nfsd_master_proc; 109 110/* 111 * NFS server system calls 112 */ 113 114static void 115nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) 116{ 117 struct nfsrv_descript nd; 118 struct nfsrvcache *rp = NULL; 119 int cacherep, credflavor; 120 121 memset(&nd, 0, sizeof(nd)); 122 if (rqst->rq_vers == NFS_VER2) { 123 if (rqst->rq_proc > NFSV2PROC_STATFS || 124 newnfs_nfsv3_procid[rqst->rq_proc] == NFSPROC_NOOP) { 125 svcerr_noproc(rqst); 126 svc_freereq(rqst); 127 goto out; 128 } 129 nd.nd_procnum = newnfs_nfsv3_procid[rqst->rq_proc]; 130 nd.nd_flag = ND_NFSV2; 131 } else if (rqst->rq_vers == NFS_VER3) { 132 if (rqst->rq_proc >= NFS_V3NPROCS) { 133 svcerr_noproc(rqst); 134 svc_freereq(rqst); 135 goto out; 136 } 137 nd.nd_procnum = rqst->rq_proc; 138 nd.nd_flag = ND_NFSV3; 139 } else { 140 if (rqst->rq_proc != NFSPROC_NULL && 141 rqst->rq_proc != NFSV4PROC_COMPOUND) { 142 svcerr_noproc(rqst); 143 svc_freereq(rqst); 144 goto out; 145 } 146 nd.nd_procnum = rqst->rq_proc; 147 nd.nd_flag = ND_NFSV4; 148 } 149 150 /* 151 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - 152 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP 153 * mounts. 154 */ 155 nd.nd_mrep = rqst->rq_args; 156 rqst->rq_args = NULL; 157 newnfs_realign(&nd.nd_mrep, M_WAITOK); 158 nd.nd_md = nd.nd_mrep; 159 nd.nd_dpos = mtod(nd.nd_md, caddr_t); 160 nd.nd_nam = svc_getrpccaller(rqst); 161 nd.nd_nam2 = rqst->rq_addr; 162 nd.nd_mreq = NULL; 163 nd.nd_cred = NULL; 164 165 if (nfs_privport && (nd.nd_flag & ND_NFSV4) == 0) { 166 /* Check if source port is privileged */ 167 u_short port; 168 struct sockaddr *nam = nd.nd_nam; 169 struct sockaddr_in *sin; 170 171 sin = (struct sockaddr_in *)nam; 172 /* 173 * INET/INET6 - same code: 174 * sin_port and sin6_port are at same offset 175 */ 176 port = ntohs(sin->sin_port); 177 if (port >= IPPORT_RESERVED && 178 nd.nd_procnum != NFSPROC_NULL) { 179#ifdef INET6 180 char b6[INET6_ADDRSTRLEN]; 181#if defined(KLD_MODULE) 182 /* Do not use ip6_sprintf: the nfs module should work without INET6. */ 183#define ip6_sprintf(buf, a) \ 184 (sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \ 185 (a)->s6_addr16[0], (a)->s6_addr16[1], \ 186 (a)->s6_addr16[2], (a)->s6_addr16[3], \ 187 (a)->s6_addr16[4], (a)->s6_addr16[5], \ 188 (a)->s6_addr16[6], (a)->s6_addr16[7]), \ 189 (buf)) 190#endif 191#endif 192 printf("NFS request from unprivileged port (%s:%d)\n", 193#ifdef INET6 194 sin->sin_family == AF_INET6 ? 195 ip6_sprintf(b6, &satosin6(sin)->sin6_addr) : 196#if defined(KLD_MODULE) 197#undef ip6_sprintf 198#endif 199#endif 200 inet_ntoa(sin->sin_addr), port); 201 svcerr_weakauth(rqst); 202 svc_freereq(rqst); 203 m_freem(nd.nd_mrep); 204 goto out; 205 } 206 } 207 208 if (nd.nd_procnum != NFSPROC_NULL) { 209 if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) { 210 svcerr_weakauth(rqst); 211 svc_freereq(rqst); 212 m_freem(nd.nd_mrep); 213 goto out; 214 } 215 216 /* Set the flag based on credflavor */ 217 if (credflavor == RPCSEC_GSS_KRB5) { 218 nd.nd_flag |= ND_GSS; 219 } else if (credflavor == RPCSEC_GSS_KRB5I) { 220 nd.nd_flag |= (ND_GSS | ND_GSSINTEGRITY); 221 } else if (credflavor == RPCSEC_GSS_KRB5P) { 222 nd.nd_flag |= (ND_GSS | ND_GSSPRIVACY); 223 } else if (credflavor != AUTH_SYS) { 224 svcerr_weakauth(rqst); 225 svc_freereq(rqst); 226 m_freem(nd.nd_mrep); 227 goto out; 228 } 229 230#ifdef MAC 231 mac_cred_associate_nfsd(nd.nd_cred); 232#endif 233 /* 234 * Get a refcnt (shared lock) on nfsd_suspend_lock. 235 * NFSSVC_SUSPENDNFSD will take an exclusive lock on 236 * nfsd_suspend_lock to suspend these threads. 237 * This must be done here, before the check of 238 * nfsv4root exports by nfsvno_v4rootexport(). 239 */ 240 NFSLOCKV4ROOTMUTEX(); 241 nfsv4_getref(&nfsd_suspend_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, 242 NULL); 243 NFSUNLOCKV4ROOTMUTEX(); 244 245 if ((nd.nd_flag & ND_NFSV4) != 0) { 246 nd.nd_repstat = nfsvno_v4rootexport(&nd); 247 if (nd.nd_repstat != 0) { 248 NFSLOCKV4ROOTMUTEX(); 249 nfsv4_relref(&nfsd_suspend_lock); 250 NFSUNLOCKV4ROOTMUTEX(); 251 svcerr_weakauth(rqst); 252 svc_freereq(rqst); 253 m_freem(nd.nd_mrep); 254 goto out; 255 } 256 } 257 258 cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp); 259 NFSLOCKV4ROOTMUTEX(); 260 nfsv4_relref(&nfsd_suspend_lock); 261 NFSUNLOCKV4ROOTMUTEX(); 262 } else { 263 NFSMGET(nd.nd_mreq); 264 nd.nd_mreq->m_len = 0; 265 cacherep = RC_REPLY; 266 } 267 if (nd.nd_mrep != NULL) 268 m_freem(nd.nd_mrep); 269 270 if (nd.nd_cred != NULL) 271 crfree(nd.nd_cred); 272 273 if (cacherep == RC_DROPIT) { 274 if (nd.nd_mreq != NULL) 275 m_freem(nd.nd_mreq); 276 svc_freereq(rqst); 277 goto out; 278 } 279 280 if (nd.nd_mreq == NULL) { 281 svcerr_decode(rqst); 282 svc_freereq(rqst); 283 goto out; 284 } 285 286 if (nd.nd_repstat & NFSERR_AUTHERR) { 287 svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); 288 if (nd.nd_mreq != NULL) 289 m_freem(nd.nd_mreq); 290 } else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) { 291 svcerr_systemerr(rqst); 292 } 293 if (rp != NULL) { 294 nfsrvd_sentcache(rp, (rqst->rq_reply_seq != 0 || 295 SVC_ACK(xprt, NULL)), rqst->rq_reply_seq); 296 } 297 svc_freereq(rqst); 298 299out: 300 if (softdep_ast_cleanup != NULL) 301 softdep_ast_cleanup(); 302 NFSEXITCODE(0); 303} 304 305/* 306 * Check the cache and, optionally, do the RPC. 307 * Return the appropriate cache response. 308 */ 309static int 310nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt, 311 struct nfsrvcache **rpp) 312{ 313 struct thread *td = curthread; 314 int cacherep = RC_DOIT, isdgram, taglen = -1; 315 struct mbuf *m; 316 u_char tag[NFSV4_SMALLSTR + 1], *tagstr = NULL; 317 u_int32_t minorvers = 0; 318 uint32_t ack; 319 320 *rpp = NULL; 321 if (nd->nd_nam2 == NULL) { 322 nd->nd_flag |= ND_STREAMSOCK; 323 isdgram = 0; 324 } else { 325 isdgram = 1; 326 } 327 328 /* 329 * Two cases: 330 * 1 - For NFSv2 over UDP, if we are near our malloc/mget 331 * limit, just drop the request. There is no 332 * NFSERR_RESOURCE or NFSERR_DELAY for NFSv2 and the 333 * client will timeout/retry over UDP in a little while. 334 * 2 - nd_repstat == 0 && nd_mreq == NULL, which 335 * means a normal nfs rpc, so check the cache 336 */ 337 if ((nd->nd_flag & ND_NFSV2) && nd->nd_nam2 != NULL && 338 nfsrv_mallocmget_limit()) { 339 cacherep = RC_DROPIT; 340 } else { 341 /* 342 * For NFSv3, play it safe and assume that the client is 343 * doing retries on the same TCP connection. 344 */ 345 if ((nd->nd_flag & (ND_NFSV4 | ND_STREAMSOCK)) == 346 ND_STREAMSOCK) 347 nd->nd_flag |= ND_SAMETCPCONN; 348 nd->nd_retxid = xid; 349 nd->nd_tcpconntime = NFSD_MONOSEC; 350 nd->nd_sockref = xprt->xp_sockref; 351 if ((nd->nd_flag & ND_NFSV4) != 0) 352 nfsd_getminorvers(nd, tag, &tagstr, &taglen, 353 &minorvers); 354 if ((nd->nd_flag & ND_NFSV41) != 0) 355 /* NFSv4.1 caches replies in the session slots. */ 356 cacherep = RC_DOIT; 357 else { 358 cacherep = nfsrvd_getcache(nd); 359 ack = 0; 360 SVC_ACK(xprt, &ack); 361 nfsrc_trimcache(xprt->xp_sockref, ack, 0); 362 } 363 } 364 365 /* 366 * Handle the request. There are three cases. 367 * RC_DOIT - do the RPC 368 * RC_REPLY - return the reply already created 369 * RC_DROPIT - just throw the request away 370 */ 371 if (cacherep == RC_DOIT) { 372 if ((nd->nd_flag & ND_NFSV41) != 0) 373 nd->nd_xprt = xprt; 374 nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers, td); 375 if ((nd->nd_flag & ND_NFSV41) != 0) { 376 if (nd->nd_repstat != NFSERR_REPLYFROMCACHE && 377 (nd->nd_flag & ND_SAVEREPLY) != 0) { 378 /* Cache a copy of the reply. */ 379 m = m_copym(nd->nd_mreq, 0, M_COPYALL, 380 M_WAITOK); 381 } else 382 m = NULL; 383 if ((nd->nd_flag & ND_HASSEQUENCE) != 0) 384 nfsrv_cache_session(nd->nd_sessionid, 385 nd->nd_slotid, nd->nd_repstat, &m); 386 if (nd->nd_repstat == NFSERR_REPLYFROMCACHE) 387 nd->nd_repstat = 0; 388 cacherep = RC_REPLY; 389 } else { 390 if (nd->nd_repstat == NFSERR_DONTREPLY) 391 cacherep = RC_DROPIT; 392 else 393 cacherep = RC_REPLY; 394 *rpp = nfsrvd_updatecache(nd); 395 } 396 } 397 if (tagstr != NULL && taglen > NFSV4_SMALLSTR) 398 free(tagstr, M_TEMP); 399 400 NFSEXITCODE2(0, nd); 401 return (cacherep); 402} 403 404static void 405nfssvc_loss(SVCXPRT *xprt) 406{ 407 uint32_t ack; 408 409 ack = 0; 410 SVC_ACK(xprt, &ack); 411 nfsrc_trimcache(xprt->xp_sockref, ack, 1); 412} 413 414/* 415 * Adds a socket to the list for servicing by nfsds. 416 */ 417int 418nfsrvd_addsock(struct file *fp) 419{ 420 int siz; 421 struct socket *so; 422 int error = 0; 423 SVCXPRT *xprt; 424 static u_int64_t sockref = 0; 425 426 so = fp->f_data; 427 428 siz = sb_max_adj; 429 error = soreserve(so, siz, siz); 430 if (error) 431 goto out; 432 433 /* 434 * Steal the socket from userland so that it doesn't close 435 * unexpectedly. 436 */ 437 if (so->so_type == SOCK_DGRAM) 438 xprt = svc_dg_create(nfsrvd_pool, so, 0, 0); 439 else 440 xprt = svc_vc_create(nfsrvd_pool, so, 0, 0); 441 if (xprt) { 442 fp->f_ops = &badfileops; 443 fp->f_data = NULL; 444 xprt->xp_sockref = ++sockref; 445 if (nfs_minvers == NFS_VER2) 446 svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, 447 NULL); 448 if (nfs_minvers <= NFS_VER3 && nfs_maxvers >= NFS_VER3) 449 svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, 450 NULL); 451 if (nfs_maxvers >= NFS_VER4) 452 svc_reg(xprt, NFS_PROG, NFS_VER4, nfssvc_program, 453 NULL); 454 if (so->so_type == SOCK_STREAM) 455 svc_loss_reg(xprt, nfssvc_loss); 456 SVC_RELEASE(xprt); 457 } 458 459out: 460 NFSEXITCODE(error); 461 return (error); 462} 463 464/* 465 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 466 * until it is killed by a signal. 467 */ 468int 469nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) 470{ 471 char principal[MAXHOSTNAMELEN + 5]; 472 struct proc *p; 473 int error = 0; 474 bool_t ret2, ret3, ret4; 475 476 error = copyinstr(args->principal, principal, sizeof (principal), 477 NULL); 478 if (error) 479 goto out; 480 481 /* 482 * Only the first nfsd actually does any work. The RPC code 483 * adds threads to it as needed. Any extra processes offered 484 * by nfsd just exit. If nfsd is new enough, it will call us 485 * once with a structure that specifies how many threads to 486 * use. 487 */ 488 NFSD_LOCK(); 489 if (newnfs_numnfsd == 0) { 490 p = td->td_proc; 491 PROC_LOCK(p); 492 p->p_flag2 |= P2_AST_SU; 493 PROC_UNLOCK(p); 494 newnfs_numnfsd++; 495 496 NFSD_UNLOCK(); 497 498 /* An empty string implies AUTH_SYS only. */ 499 if (principal[0] != '\0') { 500 ret2 = rpc_gss_set_svc_name_call(principal, 501 "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, NFS_VER2); 502 ret3 = rpc_gss_set_svc_name_call(principal, 503 "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, NFS_VER3); 504 ret4 = rpc_gss_set_svc_name_call(principal, 505 "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, NFS_VER4); 506 507 if (!ret2 || !ret3 || !ret4) 508 printf("nfsd: can't register svc name\n"); 509 } 510 511 nfsrvd_pool->sp_minthreads = args->minthreads; 512 nfsrvd_pool->sp_maxthreads = args->maxthreads; 513 514 svc_run(nfsrvd_pool); 515 516 if (principal[0] != '\0') { 517 rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER2); 518 rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER3); 519 rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER4); 520 } 521 522 NFSD_LOCK(); 523 newnfs_numnfsd--; 524 nfsrvd_init(1); 525 PROC_LOCK(p); 526 p->p_flag2 &= ~P2_AST_SU; 527 PROC_UNLOCK(p); 528 } 529 NFSD_UNLOCK(); 530 531out: 532 NFSEXITCODE(error); 533 return (error); 534} 535 536/* 537 * Initialize the data structures for the server. 538 * Handshake with any new nfsds starting up to avoid any chance of 539 * corruption. 540 */ 541void 542nfsrvd_init(int terminating) 543{ 544 545 NFSD_LOCK_ASSERT(); 546 547 if (terminating) { 548 nfsd_master_proc = NULL; 549 NFSD_UNLOCK(); 550 nfsrv_freeallbackchannel_xprts(); 551 svcpool_destroy(nfsrvd_pool); 552 nfsrvd_pool = NULL; 553 NFSD_LOCK(); 554 } 555 556 NFSD_UNLOCK(); 557 558 nfsrvd_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_nfsd)); 559 nfsrvd_pool->sp_rcache = NULL; 560 nfsrvd_pool->sp_assign = fhanew_assign; 561 nfsrvd_pool->sp_done = fha_nd_complete; 562 563 NFSD_LOCK(); 564} 565 566