nfs_nfsdkrpc.c revision 192780
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: head/sys/fs/nfsserver/nfs_nfsdkrpc.c 192780 2009-05-26 01:09:33Z rmacklem $"); 36 37#include "opt_inet6.h" 38#include "opt_kgssapi.h" 39 40#include <fs/nfs/nfsport.h> 41 42#include <rpc/rpc.h> 43#include <rpc/rpcsec_gss.h> 44 45NFSDLOCKMUTEX; 46 47/* 48 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 49 */ 50static int newnfs_nfsv3_procid[NFS_V3NPROCS] = { 51 NFSPROC_NULL, 52 NFSPROC_GETATTR, 53 NFSPROC_SETATTR, 54 NFSPROC_NOOP, 55 NFSPROC_LOOKUP, 56 NFSPROC_READLINK, 57 NFSPROC_READ, 58 NFSPROC_NOOP, 59 NFSPROC_WRITE, 60 NFSPROC_CREATE, 61 NFSPROC_REMOVE, 62 NFSPROC_RENAME, 63 NFSPROC_LINK, 64 NFSPROC_SYMLINK, 65 NFSPROC_MKDIR, 66 NFSPROC_RMDIR, 67 NFSPROC_READDIR, 68 NFSPROC_FSSTAT, 69 NFSPROC_NOOP, 70 NFSPROC_NOOP, 71 NFSPROC_NOOP, 72 NFSPROC_NOOP, 73}; 74 75 76SYSCTL_DECL(_vfs_newnfs); 77 78SVCPOOL *nfsrvd_pool; 79 80static int nfs_privport = 0; 81SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_privport, CTLFLAG_RW, 82 &nfs_privport, 0, 83 "Only allow clients using a privileged port for NFSv2 and 3"); 84 85static int nfs_proc(struct nfsrv_descript *, u_int32_t, struct socket *, 86 u_int64_t, struct nfsrvcache **); 87 88extern u_long sb_max_adj; 89extern int newnfs_numnfsd; 90 91/* 92 * NFS server system calls 93 */ 94 95static void 96nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) 97{ 98 struct nfsrv_descript nd; 99 struct nfsrvcache *rp = NULL; 100 int cacherep, credflavor; 101 102 memset(&nd, 0, sizeof(nd)); 103 if (rqst->rq_vers == NFS_VER2) { 104 if (rqst->rq_proc > NFSV2PROC_STATFS) { 105 svcerr_noproc(rqst); 106 svc_freereq(rqst); 107 return; 108 } 109 nd.nd_procnum = newnfs_nfsv3_procid[rqst->rq_proc]; 110 nd.nd_flag = ND_NFSV2; 111 } else if (rqst->rq_vers == NFS_VER3) { 112 if (rqst->rq_proc >= NFS_V3NPROCS) { 113 svcerr_noproc(rqst); 114 svc_freereq(rqst); 115 return; 116 } 117 nd.nd_procnum = rqst->rq_proc; 118 nd.nd_flag = ND_NFSV3; 119 } else { 120 if (rqst->rq_proc != NFSPROC_NULL && 121 rqst->rq_proc != NFSV4PROC_COMPOUND) { 122 svcerr_noproc(rqst); 123 svc_freereq(rqst); 124 return; 125 } 126 nd.nd_procnum = rqst->rq_proc; 127 nd.nd_flag = ND_NFSV4; 128 } 129 130 /* 131 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - 132 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP 133 * mounts. 134 */ 135 nd.nd_mrep = rqst->rq_args; 136 rqst->rq_args = NULL; 137 newnfs_realign(&nd.nd_mrep); 138 nd.nd_md = nd.nd_mrep; 139 nd.nd_dpos = mtod(nd.nd_md, caddr_t); 140 nd.nd_nam = svc_getrpccaller(rqst); 141 nd.nd_nam2 = rqst->rq_addr; 142 nd.nd_mreq = NULL; 143 nd.nd_cred = NULL; 144 145 if (nfs_privport && (nd.nd_flag & ND_NFSV4) == 0) { 146 /* Check if source port is privileged */ 147 u_short port; 148 struct sockaddr *nam = nd.nd_nam; 149 struct sockaddr_in *sin; 150 151 sin = (struct sockaddr_in *)nam; 152 /* 153 * INET/INET6 - same code: 154 * sin_port and sin6_port are at same offset 155 */ 156 port = ntohs(sin->sin_port); 157 if (port >= IPPORT_RESERVED && 158 nd.nd_procnum != NFSPROC_NULL) { 159#ifdef INET6 160 char b6[INET6_ADDRSTRLEN]; 161#if defined(KLD_MODULE) 162 /* Do not use ip6_sprintf: the nfs module should work without INET6. */ 163#define ip6_sprintf(buf, a) \ 164 (sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \ 165 (a)->s6_addr16[0], (a)->s6_addr16[1], \ 166 (a)->s6_addr16[2], (a)->s6_addr16[3], \ 167 (a)->s6_addr16[4], (a)->s6_addr16[5], \ 168 (a)->s6_addr16[6], (a)->s6_addr16[7]), \ 169 (buf)) 170#endif 171#endif 172 printf("NFS request from unprivileged port (%s:%d)\n", 173#ifdef INET6 174 sin->sin_family == AF_INET6 ? 175 ip6_sprintf(b6, &satosin6(sin)->sin6_addr) : 176#if defined(KLD_MODULE) 177#undef ip6_sprintf 178#endif 179#endif 180 inet_ntoa(sin->sin_addr), port); 181 svcerr_weakauth(rqst); 182 svc_freereq(rqst); 183 m_freem(nd.nd_mrep); 184 return; 185 } 186 } 187 188 if (nd.nd_procnum != NFSPROC_NULL) { 189 if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) { 190 svcerr_weakauth(rqst); 191 svc_freereq(rqst); 192 m_freem(nd.nd_mrep); 193 return; 194 } 195 196 /* Set the flag based on credflavor */ 197 if (credflavor == RPCSEC_GSS_KRB5) { 198 nd.nd_flag |= ND_GSS; 199 } else if (credflavor == RPCSEC_GSS_KRB5I) { 200 nd.nd_flag |= (ND_GSS | ND_GSSINTEGRITY); 201 } else if (credflavor == RPCSEC_GSS_KRB5P) { 202 nd.nd_flag |= (ND_GSS | ND_GSSPRIVACY); 203 } else if (credflavor != AUTH_SYS) { 204 svcerr_weakauth(rqst); 205 svc_freereq(rqst); 206 m_freem(nd.nd_mrep); 207 return; 208 } 209 210#ifdef MAC 211 mac_cred_associate_nfsd(nd.nd_cred); 212#endif 213 if ((nd.nd_flag & ND_NFSV4) != 0) { 214 nd.nd_repstat = nfsvno_v4rootexport(&nd); 215 if (nd.nd_repstat != 0) { 216 svcerr_weakauth(rqst); 217 svc_freereq(rqst); 218 m_freem(nd.nd_mrep); 219 return; 220 } 221 } 222 223 cacherep = nfs_proc(&nd, rqst->rq_xid, xprt->xp_socket, 224 xprt->xp_sockref, &rp); 225 } else { 226 NFSMGET(nd.nd_mreq); 227 nd.nd_mreq->m_len = 0; 228 cacherep = RC_REPLY; 229 } 230 if (nd.nd_mrep != NULL) 231 m_freem(nd.nd_mrep); 232 233 if (nd.nd_cred != NULL) 234 crfree(nd.nd_cred); 235 236 if (cacherep == RC_DROPIT) { 237 if (nd.nd_mreq != NULL) 238 m_freem(nd.nd_mreq); 239 svc_freereq(rqst); 240 return; 241 } 242 243 if (nd.nd_mreq == NULL) { 244 svcerr_decode(rqst); 245 svc_freereq(rqst); 246 return; 247 } 248 249 if (nd.nd_repstat & NFSERR_AUTHERR) { 250 svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); 251 if (nd.nd_mreq != NULL) 252 m_freem(nd.nd_mreq); 253 } else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) { 254 svcerr_systemerr(rqst); 255 } 256 if (rp != NULL) 257 nfsrvd_sentcache(rp, xprt->xp_socket, 0); 258 svc_freereq(rqst); 259} 260 261/* 262 * Check the cache and, optionally, do the RPC. 263 * Return the appropriate cache response. 264 */ 265static int 266nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, struct socket *so, 267 u_int64_t sockref, struct nfsrvcache **rpp) 268{ 269 struct thread *td = curthread; 270 int cacherep = RC_DOIT, isdgram; 271 272 *rpp = NULL; 273 if (nd->nd_nam2 == NULL) { 274 nd->nd_flag |= ND_STREAMSOCK; 275 isdgram = 0; 276 } else { 277 isdgram = 1; 278 } 279 NFSGETTIME(&nd->nd_starttime); 280 281 /* 282 * Two cases: 283 * 1 - For NFSv2 over UDP, if we are near our malloc/mget 284 * limit, just drop the request. There is no 285 * NFSERR_RESOURCE or NFSERR_DELAY for NFSv2 and the 286 * client will timeout/retry over UDP in a little while. 287 * 2 - nd_repstat == 0 && nd_mreq == NULL, which 288 * means a normal nfs rpc, so check the cache 289 */ 290 if ((nd->nd_flag & ND_NFSV2) && nd->nd_nam2 != NULL && 291 nfsrv_mallocmget_limit()) { 292 cacherep = RC_DROPIT; 293 } else { 294 /* 295 * For NFSv3, play it safe and assume that the client is 296 * doing retries on the same TCP connection. 297 */ 298 if ((nd->nd_flag & (ND_NFSV4 | ND_STREAMSOCK)) == 299 ND_STREAMSOCK) 300 nd->nd_flag |= ND_SAMETCPCONN; 301 nd->nd_retxid = xid; 302 nd->nd_tcpconntime = NFSD_MONOSEC; 303 nd->nd_sockref = sockref; 304 cacherep = nfsrvd_getcache(nd, so); 305 } 306 307 /* 308 * Handle the request. There are three cases. 309 * RC_DOIT - do the RPC 310 * RC_REPLY - return the reply already created 311 * RC_DROPIT - just throw the request away 312 */ 313 if (cacherep == RC_DOIT) { 314 nfsrvd_dorpc(nd, isdgram, td); 315 if (nd->nd_repstat == NFSERR_DONTREPLY) 316 cacherep = RC_DROPIT; 317 else 318 cacherep = RC_REPLY; 319 *rpp = nfsrvd_updatecache(nd, so); 320 } 321 return (cacherep); 322} 323 324/* 325 * Adds a socket to the list for servicing by nfsds. 326 */ 327int 328nfsrvd_addsock(struct file *fp) 329{ 330 int siz; 331 struct socket *so; 332 int error; 333 SVCXPRT *xprt; 334 static u_int64_t sockref = 0; 335 336 so = fp->f_data; 337 338 siz = sb_max_adj; 339 error = soreserve(so, siz, siz); 340 if (error) { 341 return (error); 342 } 343 344 /* 345 * Steal the socket from userland so that it doesn't close 346 * unexpectedly. 347 */ 348 if (so->so_type == SOCK_DGRAM) 349 xprt = svc_dg_create(nfsrvd_pool, so, 0, 0); 350 else 351 xprt = svc_vc_create(nfsrvd_pool, so, 0, 0); 352 if (xprt) { 353 fp->f_ops = &badfileops; 354 fp->f_data = NULL; 355 xprt->xp_sockref = ++sockref; 356 svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL); 357 svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL); 358 svc_reg(xprt, NFS_PROG, NFS_VER4, nfssvc_program, NULL); 359 } 360 361 return (0); 362} 363 364/* 365 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 366 * until it is killed by a signal. 367 */ 368int 369nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) 370{ 371#ifdef KGSSAPI 372 char principal[MAXHOSTNAMELEN + 5]; 373 int error; 374 bool_t ret2, ret3, ret4; 375#endif 376 377#ifdef KGSSAPI 378 error = copyinstr(args->principal, principal, sizeof (principal), 379 NULL); 380 if (error) 381 return (error); 382#endif 383 384 /* 385 * Only the first nfsd actually does any work. The RPC code 386 * adds threads to it as needed. Any extra processes offered 387 * by nfsd just exit. If nfsd is new enough, it will call us 388 * once with a structure that specifies how many threads to 389 * use. 390 */ 391 NFSD_LOCK(); 392 if (newnfs_numnfsd == 0) { 393 newnfs_numnfsd++; 394 395 NFSD_UNLOCK(); 396 397#ifdef KGSSAPI 398 /* An empty string implies AUTH_SYS only. */ 399 if (principal[0] != '\0') { 400 ret2 = rpc_gss_set_svc_name(principal, "kerberosv5", 401 GSS_C_INDEFINITE, NFS_PROG, NFS_VER2); 402 ret3 = rpc_gss_set_svc_name(principal, "kerberosv5", 403 GSS_C_INDEFINITE, NFS_PROG, NFS_VER3); 404 ret4 = rpc_gss_set_svc_name(principal, "kerberosv5", 405 GSS_C_INDEFINITE, NFS_PROG, NFS_VER4); 406 407 if (!ret2 || !ret3 || !ret4) { 408 NFSD_LOCK(); 409 newnfs_numnfsd--; 410 nfsrvd_init(1); 411 NFSD_UNLOCK(); 412 return (EAUTH); 413 } 414 } 415#endif 416 417 nfsrvd_pool->sp_minthreads = args->minthreads; 418 nfsrvd_pool->sp_maxthreads = args->maxthreads; 419 420 svc_run(nfsrvd_pool); 421 422#ifdef KGSSAPI 423 if (principal[0] != '\0') { 424 rpc_gss_clear_svc_name(NFS_PROG, NFS_VER2); 425 rpc_gss_clear_svc_name(NFS_PROG, NFS_VER3); 426 rpc_gss_clear_svc_name(NFS_PROG, NFS_VER4); 427 } 428#endif 429 430 NFSD_LOCK(); 431 newnfs_numnfsd--; 432 nfsrvd_init(1); 433 } 434 NFSD_UNLOCK(); 435 436 return (0); 437} 438 439/* 440 * Initialize the data structures for the server. 441 * Handshake with any new nfsds starting up to avoid any chance of 442 * corruption. 443 */ 444void 445nfsrvd_init(int terminating) 446{ 447 448 NFSD_LOCK_ASSERT(); 449 450 if (terminating) { 451 NFSD_UNLOCK(); 452 svcpool_destroy(nfsrvd_pool); 453 nfsrvd_pool = NULL; 454 NFSD_LOCK(); 455 } 456 457 NFSD_UNLOCK(); 458 459 nfsrvd_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_newnfs)); 460 nfsrvd_pool->sp_rcache = NULL; 461 nfsrvd_pool->sp_assign = NULL; 462 nfsrvd_pool->sp_done = NULL; 463 464 NFSD_LOCK(); 465} 466 467