1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/errno.h> 28 #include <sys/vfs.h> 29 #include <sys/vnode.h> 30 #include <sys/cred.h> 31 #include <sys/cmn_err.h> 32 #include <sys/systm.h> 33 #include <sys/kmem.h> 34 #include <sys/pathname.h> 35 #include <sys/utsname.h> 36 #include <sys/debug.h> 37 #include <sys/door.h> 38 #include <sys/sdt.h> 39 40 #include <rpc/types.h> 41 #include <rpc/auth.h> 42 #include <rpc/clnt.h> 43 44 #include <nfs/nfs.h> 45 #include <nfs/export.h> 46 #include <nfs/nfs_clnt.h> 47 #include <nfs/auth.h> 48 49 #define EQADDR(a1, a2) \ 50 (bcmp((char *)(a1)->buf, (char *)(a2)->buf, (a1)->len) == 0 && \ 51 (a1)->len == (a2)->len) 52 53 static struct knetconfig auth_knconf; 54 static servinfo_t svp; 55 static clinfo_t ci; 56 57 static struct kmem_cache *exi_cache_handle; 58 static void exi_cache_reclaim(void *); 59 static void exi_cache_trim(struct exportinfo *exi); 60 61 int nfsauth_cache_hit; 62 int nfsauth_cache_miss; 63 int nfsauth_cache_reclaim; 64 65 /* 66 * Number of seconds to wait for an NFSAUTH upcall. 67 */ 68 static int nfsauth_timeout = 20; 69 70 /* 71 * mountd is a server-side only daemon. This will need to be 72 * revisited if the NFS server is ever made zones-aware. 73 */ 74 kmutex_t mountd_lock; 75 door_handle_t mountd_dh; 76 77 void 78 mountd_args(uint_t did) 79 { 80 mutex_enter(&mountd_lock); 81 if (mountd_dh) 82 door_ki_rele(mountd_dh); 83 mountd_dh = door_ki_lookup(did); 84 mutex_exit(&mountd_lock); 85 } 86 87 void 88 nfsauth_init(void) 89 { 90 /* 91 * mountd can be restarted by smf(5). We need to make sure 92 * the updated door handle will safely make it to mountd_dh 93 */ 94 mutex_init(&mountd_lock, NULL, MUTEX_DEFAULT, NULL); 95 96 /* 97 * Allocate nfsauth cache handle 98 */ 99 exi_cache_handle = kmem_cache_create("exi_cache_handle", 100 sizeof (struct auth_cache), 0, NULL, NULL, 101 exi_cache_reclaim, NULL, NULL, 0); 102 } 103 104 /* 105 * Finalization routine for nfsauth. It is important to call this routine 106 * before destroying the exported_lock. 107 */ 108 void 109 nfsauth_fini(void) 110 { 111 /* 112 * Deallocate nfsauth cache handle 113 */ 114 kmem_cache_destroy(exi_cache_handle); 115 } 116 117 /* 118 * Convert the address in a netbuf to 119 * a hash index for the auth_cache table. 120 */ 121 static int 122 hash(struct netbuf *a) 123 { 124 int i, h = 0; 125 126 for (i = 0; i < a->len; i++) 127 h ^= a->buf[i]; 128 129 return (h & (AUTH_TABLESIZE - 1)); 130 } 131 132 /* 133 * Mask out the components of an 134 * address that do not identify 135 * a host. For socket addresses the 136 * masking gets rid of the port number. 137 */ 138 static void 139 addrmask(struct netbuf *addr, struct netbuf *mask) 140 { 141 int i; 142 143 for (i = 0; i < addr->len; i++) 144 addr->buf[i] &= mask->buf[i]; 145 } 146 147 /* 148 * nfsauth4_access is used for NFS V4 auth checking. Besides doing 149 * the common nfsauth_access(), it will check if the client can 150 * have a limited access to this vnode even if the security flavor 151 * used does not meet the policy. 152 */ 153 int 154 nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req) 155 { 156 int access; 157 158 access = nfsauth_access(exi, req); 159 160 /* 161 * There are cases that the server needs to allow the client 162 * to have a limited view. 163 * 164 * e.g. 165 * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw" 166 * /export/home is shared as "sec=sys,rw" 167 * 168 * When the client mounts /export with sec=sys, the client 169 * would get a limited view with RO access on /export to see 170 * "home" only because the client is allowed to access 171 * /export/home with auth_sys. 172 */ 173 if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { 174 /* 175 * Allow ro permission with LIMITED view if there is a 176 * sub-dir exported under vp. 177 */ 178 if (has_visible(exi, vp)) 179 return (NFSAUTH_LIMITED); 180 } 181 182 return (access); 183 } 184 185 static void 186 sys_log(const char *msg) 187 { 188 static time_t tstamp = 0; 189 time_t now; 190 191 /* 192 * msg is shown (at most) once per minute 193 */ 194 now = gethrestime_sec(); 195 if ((tstamp + 60) < now) { 196 tstamp = now; 197 cmn_err(CE_WARN, msg); 198 } 199 } 200 201 /* 202 * Get the access information from the cache or callup to the mountd 203 * to get and cache the access information in the kernel. 204 */ 205 int 206 nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor) 207 { 208 struct netbuf addr; 209 struct netbuf *claddr; 210 struct auth_cache **head; 211 struct auth_cache *ap; 212 int access; 213 varg_t varg = {0}; 214 nfsauth_res_t res = {0}; 215 XDR xdrs_a; 216 XDR xdrs_r; 217 size_t absz; 218 caddr_t abuf; 219 size_t rbsz = (size_t)(BYTES_PER_XDR_UNIT * 2); 220 char result[BYTES_PER_XDR_UNIT * 2] = {0}; 221 caddr_t rbuf = (caddr_t)&result; 222 int last = 0; 223 door_arg_t da; 224 door_info_t di; 225 door_handle_t dh; 226 uint_t ntries = 0; 227 228 /* 229 * Now check whether this client already 230 * has an entry for this flavor in the cache 231 * for this export. 232 * Get the caller's address, mask off the 233 * parts of the address that do not identify 234 * the host (port number, etc), and then hash 235 * it to find the chain of cache entries. 236 */ 237 238 claddr = svc_getrpccaller(req->rq_xprt); 239 addr = *claddr; 240 addr.buf = kmem_alloc(addr.len, KM_SLEEP); 241 bcopy(claddr->buf, addr.buf, claddr->len); 242 addrmask(&addr, svc_getaddrmask(req->rq_xprt)); 243 head = &exi->exi_cache[hash(&addr)]; 244 245 rw_enter(&exi->exi_cache_lock, RW_READER); 246 for (ap = *head; ap; ap = ap->auth_next) { 247 if (EQADDR(&addr, &ap->auth_addr) && flavor == ap->auth_flavor) 248 break; 249 } 250 if (ap) { /* cache hit */ 251 access = ap->auth_access; 252 ap->auth_time = gethrestime_sec(); 253 nfsauth_cache_hit++; 254 } 255 256 rw_exit(&exi->exi_cache_lock); 257 258 if (ap) { 259 kmem_free(addr.buf, addr.len); 260 return (access); 261 } 262 263 nfsauth_cache_miss++; 264 265 /* 266 * No entry in the cache for this client/flavor 267 * so we need to call the nfsauth service in the 268 * mount daemon. 269 */ 270 retry: 271 mutex_enter(&mountd_lock); 272 dh = mountd_dh; 273 if (dh) 274 door_ki_hold(dh); 275 mutex_exit(&mountd_lock); 276 277 if (dh == NULL) { 278 /* 279 * The rendezvous point has not been established yet ! 280 * This could mean that either mountd(1m) has not yet 281 * been started or that _this_ routine nuked the door 282 * handle after receiving an EINTR for a REVOKED door. 283 * 284 * Returning NFSAUTH_DROP will cause the NFS client 285 * to retransmit the request, so let's try to be more 286 * rescillient and attempt for ntries before we bail. 287 */ 288 if (++ntries % NFSAUTH_DR_TRYCNT) { 289 delay(hz); 290 goto retry; 291 } 292 sys_log("nfsauth: mountd has not established door"); 293 kmem_free(addr.buf, addr.len); 294 return (NFSAUTH_DROP); 295 } 296 ntries = 0; 297 varg.vers = V_PROTO; 298 varg.arg_u.arg.cmd = NFSAUTH_ACCESS; 299 varg.arg_u.arg.areq.req_client.n_len = addr.len; 300 varg.arg_u.arg.areq.req_client.n_bytes = addr.buf; 301 varg.arg_u.arg.areq.req_netid = svc_getnetid(req->rq_xprt); 302 varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; 303 varg.arg_u.arg.areq.req_flavor = flavor; 304 305 /* 306 * Setup the XDR stream for encoding the arguments. Notice that 307 * in addition to the args having variable fields (req_netid and 308 * req_path), the argument data structure is itself versioned, 309 * so we need to make sure we can size the arguments buffer 310 * appropriately to encode all the args. If we can't get sizing 311 * info _or_ properly encode the arguments, there's really no 312 * point in continuting, so we fail the request. 313 */ 314 DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); 315 if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) { 316 door_ki_rele(dh); 317 kmem_free(addr.buf, addr.len); 318 return (NFSAUTH_DENIED); 319 } 320 abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); 321 xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE); 322 if (!xdr_varg(&xdrs_a, &varg)) { 323 door_ki_rele(dh); 324 goto fail; 325 } 326 XDR_DESTROY(&xdrs_a); 327 328 /* 329 * The result (nfsauth_res_t) is always two int's, so we don't 330 * have to dynamically size (or allocate) the results buffer. 331 * Now that we've got what we need, we prep the door arguments 332 * and place the call. 333 */ 334 da.data_ptr = (char *)abuf; 335 da.data_size = absz; 336 da.desc_ptr = NULL; 337 da.desc_num = 0; 338 da.rbuf = (char *)rbuf; 339 da.rsize = rbsz; 340 341 switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { 342 case 0: /* Success */ 343 if (da.data_ptr != da.rbuf && da.data_size == 0) { 344 /* 345 * The door_return that contained the data 346 * failed ! We're here because of the 2nd 347 * door_return (w/o data) such that we can 348 * get control of the thread (and exit 349 * gracefully). 350 */ 351 DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, 352 door_arg_t *, &da); 353 door_ki_rele(dh); 354 goto fail; 355 356 } else if (rbuf != da.rbuf) { 357 /* 358 * The only time this should be true 359 * is iff userland wanted to hand us 360 * a bigger response than what we 361 * expect; that should not happen 362 * (nfsauth_res_t is only 2 int's), 363 * but we check nevertheless. 364 */ 365 rbuf = da.rbuf; 366 rbsz = da.rsize; 367 368 } else if (rbsz > da.data_size) { 369 /* 370 * We were expecting two int's; but if 371 * userland fails in encoding the XDR 372 * stream, we detect that here, since 373 * the mountd forces down only one byte 374 * in such scenario. 375 */ 376 door_ki_rele(dh); 377 goto fail; 378 } 379 door_ki_rele(dh); 380 break; 381 382 case EAGAIN: 383 /* 384 * Server out of resources; back off for a bit 385 */ 386 door_ki_rele(dh); 387 kmem_free(abuf, absz); 388 delay(hz); 389 goto retry; 390 /* NOTREACHED */ 391 392 case EINTR: 393 if (!door_ki_info(dh, &di)) { 394 if (di.di_attributes & DOOR_REVOKED) { 395 /* 396 * The server barfed and revoked 397 * the (existing) door on us; we 398 * want to wait to give smf(5) a 399 * chance to restart mountd(1m) 400 * and establish a new door handle. 401 */ 402 mutex_enter(&mountd_lock); 403 if (dh == mountd_dh) 404 mountd_dh = NULL; 405 mutex_exit(&mountd_lock); 406 door_ki_rele(dh); 407 kmem_free(abuf, absz); 408 delay(hz); 409 goto retry; 410 } 411 /* 412 * If the door was _not_ revoked on us, 413 * then more than likely we took an INTR, 414 * so we need to fail the operation. 415 */ 416 door_ki_rele(dh); 417 goto fail; 418 } 419 /* 420 * The only failure that can occur from getting 421 * the door info is EINVAL, so we let the code 422 * below handle it. 423 */ 424 /* FALLTHROUGH */ 425 426 case EBADF: 427 case EINVAL: 428 default: 429 /* 430 * If we have a stale door handle, give smf a last 431 * chance to start it by sleeping for a little bit. 432 * If we're still hosed, we'll fail the call. 433 * 434 * Since we're going to reacquire the door handle 435 * upon the retry, we opt to sleep for a bit and 436 * _not_ to clear mountd_dh. If mountd restarted 437 * and was able to set mountd_dh, we should see 438 * the new instance; if not, we won't get caught 439 * up in the retry/DELAY loop. 440 */ 441 door_ki_rele(dh); 442 if (!last) { 443 delay(hz); 444 last++; 445 goto retry; 446 } 447 sys_log("nfsauth: stale mountd door handle"); 448 goto fail; 449 } 450 451 /* 452 * No door errors encountered; setup the XDR stream for decoding 453 * the results. If we fail to decode the results, we've got no 454 * other recourse than to fail the request. 455 */ 456 xdrmem_create(&xdrs_r, rbuf, rbsz, XDR_DECODE); 457 if (!xdr_nfsauth_res(&xdrs_r, &res)) 458 goto fail; 459 XDR_DESTROY(&xdrs_r); 460 461 DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res); 462 switch (res.stat) { 463 case NFSAUTH_DR_OKAY: 464 access = res.ares.auth_perm; 465 kmem_free(abuf, absz); 466 break; 467 468 case NFSAUTH_DR_EFAIL: 469 case NFSAUTH_DR_DECERR: 470 case NFSAUTH_DR_BADCMD: 471 default: 472 fail: 473 kmem_free(addr.buf, addr.len); 474 kmem_free(abuf, absz); 475 return (NFSAUTH_DENIED); 476 /* NOTREACHED */ 477 } 478 479 /* 480 * Now cache the result on the cache chain 481 * for this export (if there's enough memory) 482 */ 483 ap = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP); 484 if (ap) { 485 ap->auth_addr = addr; 486 ap->auth_flavor = flavor; 487 ap->auth_access = access; 488 ap->auth_time = gethrestime_sec(); 489 rw_enter(&exi->exi_cache_lock, RW_WRITER); 490 ap->auth_next = *head; 491 *head = ap; 492 rw_exit(&exi->exi_cache_lock); 493 } else { 494 kmem_free(addr.buf, addr.len); 495 } 496 497 return (access); 498 } 499 500 /* 501 * Check if the requesting client has access to the filesystem with 502 * a given nfs flavor number which is an explicitly shared flavor. 503 */ 504 int 505 nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, 506 int flavor, int perm) 507 { 508 int access; 509 510 if (! (perm & M_4SEC_EXPORTED)) { 511 return (NFSAUTH_DENIED); 512 } 513 514 /* 515 * Optimize if there are no lists 516 */ 517 if ((perm & (M_ROOT|M_NONE)) == 0) { 518 perm &= ~M_4SEC_EXPORTED; 519 if (perm == M_RO) 520 return (NFSAUTH_RO); 521 if (perm == M_RW) 522 return (NFSAUTH_RW); 523 } 524 525 access = nfsauth_cache_get(exi, req, flavor); 526 527 return (access); 528 } 529 530 int 531 nfsauth_access(struct exportinfo *exi, struct svc_req *req) 532 { 533 int access, mapaccess; 534 struct secinfo *sp; 535 int i, flavor, perm; 536 int authnone_entry = -1; 537 538 /* 539 * Get the nfs flavor number from xprt. 540 */ 541 flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 542 543 /* 544 * First check the access restrictions on the filesystem. If 545 * there are no lists associated with this flavor then there's no 546 * need to make an expensive call to the nfsauth service or to 547 * cache anything. 548 */ 549 550 sp = exi->exi_export.ex_secinfo; 551 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 552 if (flavor != sp[i].s_secinfo.sc_nfsnum) { 553 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 554 authnone_entry = i; 555 continue; 556 } 557 break; 558 } 559 560 mapaccess = 0; 561 562 if (i >= exi->exi_export.ex_seccnt) { 563 /* 564 * Flavor not found, but use AUTH_NONE if it exists 565 */ 566 if (authnone_entry == -1) 567 return (NFSAUTH_DENIED); 568 flavor = AUTH_NONE; 569 mapaccess = NFSAUTH_MAPNONE; 570 i = authnone_entry; 571 } 572 573 /* 574 * If the flavor is in the ex_secinfo list, but not an explicitly 575 * shared flavor by the user, it is a result of the nfsv4 server 576 * namespace setup. We will grant an RO permission similar for 577 * a pseudo node except that this node is a shared one. 578 * 579 * e.g. flavor in (flavor) indicates that it is not explictly 580 * shared by the user: 581 * 582 * / (sys, krb5) 583 * | 584 * export #share -o sec=sys (krb5) 585 * | 586 * secure #share -o sec=krb5 587 * 588 * In this case, when a krb5 request coming in to access 589 * /export, RO permission is granted. 590 */ 591 if (!(sp[i].s_flags & M_4SEC_EXPORTED)) 592 return (mapaccess | NFSAUTH_RO); 593 594 /* 595 * Optimize if there are no lists 596 */ 597 perm = sp[i].s_flags; 598 if ((perm & (M_ROOT|M_NONE)) == 0) { 599 perm &= ~M_4SEC_EXPORTED; 600 if (perm == M_RO) 601 return (mapaccess | NFSAUTH_RO); 602 if (perm == M_RW) 603 return (mapaccess | NFSAUTH_RW); 604 } 605 606 access = nfsauth_cache_get(exi, req, flavor); 607 608 /* 609 * Client's security flavor doesn't match with "ro" or 610 * "rw" list. Try again using AUTH_NONE if present. 611 */ 612 if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) { 613 /* 614 * Have we already encountered AUTH_NONE ? 615 */ 616 if (authnone_entry != -1) { 617 mapaccess = NFSAUTH_MAPNONE; 618 access = nfsauth_cache_get(exi, req, AUTH_NONE); 619 } else { 620 /* 621 * Check for AUTH_NONE presence. 622 */ 623 for (; i < exi->exi_export.ex_seccnt; i++) { 624 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 625 mapaccess = NFSAUTH_MAPNONE; 626 access = nfsauth_cache_get(exi, req, 627 AUTH_NONE); 628 break; 629 } 630 } 631 } 632 } 633 634 if (access & NFSAUTH_DENIED) 635 access = NFSAUTH_DENIED; 636 637 return (access | mapaccess); 638 } 639 640 /* 641 * Free the nfsauth cache for a given export 642 */ 643 void 644 nfsauth_cache_free(struct exportinfo *exi) 645 { 646 int i; 647 struct auth_cache *p, *next; 648 649 for (i = 0; i < AUTH_TABLESIZE; i++) { 650 for (p = exi->exi_cache[i]; p; p = next) { 651 kmem_free(p->auth_addr.buf, p->auth_addr.len); 652 next = p->auth_next; 653 kmem_cache_free(exi_cache_handle, (void *)p); 654 } 655 } 656 } 657 658 /* 659 * Called by the kernel memory allocator when 660 * memory is low. Free unused cache entries. 661 * If that's not enough, the VM system will 662 * call again for some more. 663 */ 664 /*ARGSUSED*/ 665 void 666 exi_cache_reclaim(void *cdrarg) 667 { 668 int i; 669 struct exportinfo *exi; 670 671 rw_enter(&exported_lock, RW_READER); 672 673 for (i = 0; i < EXPTABLESIZE; i++) { 674 for (exi = exptable[i]; exi; exi = exi->exi_hash) { 675 exi_cache_trim(exi); 676 } 677 } 678 nfsauth_cache_reclaim++; 679 680 rw_exit(&exported_lock); 681 } 682 683 /* 684 * Don't reclaim entries until they've been 685 * in the cache for at least exi_cache_time 686 * seconds. 687 */ 688 time_t exi_cache_time = 60 * 60; 689 690 void 691 exi_cache_trim(struct exportinfo *exi) 692 { 693 struct auth_cache *p; 694 struct auth_cache *prev, *next; 695 int i; 696 time_t stale_time; 697 698 stale_time = gethrestime_sec() - exi_cache_time; 699 700 rw_enter(&exi->exi_cache_lock, RW_WRITER); 701 702 for (i = 0; i < AUTH_TABLESIZE; i++) { 703 704 /* 705 * Free entries that have not been 706 * used for exi_cache_time seconds. 707 */ 708 prev = NULL; 709 for (p = exi->exi_cache[i]; p; p = next) { 710 next = p->auth_next; 711 if (p->auth_time > stale_time) { 712 prev = p; 713 continue; 714 } 715 716 kmem_free(p->auth_addr.buf, p->auth_addr.len); 717 kmem_cache_free(exi_cache_handle, (void *)p); 718 if (prev == NULL) 719 exi->exi_cache[i] = next; 720 else 721 prev->auth_next = next; 722 } 723 } 724 725 rw_exit(&exi->exi_cache_lock); 726 } 727