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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/errno.h> 27 #include <sys/vfs.h> 28 #include <sys/vnode.h> 29 #include <sys/cred.h> 30 #include <sys/cmn_err.h> 31 #include <sys/systm.h> 32 #include <sys/kmem.h> 33 #include <sys/pathname.h> 34 #include <sys/utsname.h> 35 #include <sys/debug.h> 36 #include <sys/door.h> 37 #include <sys/sdt.h> 38 #include <sys/thread.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 extern pri_t minclsyspri; 62 63 int nfsauth_cache_hit; 64 int nfsauth_cache_miss; 65 int nfsauth_cache_refresh; 66 int nfsauth_cache_reclaim; 67 68 /* 69 * The lifetime of an auth cache entry: 70 * ------------------------------------ 71 * 72 * An auth cache entry is created with both the auth_time 73 * and auth_freshness times set to the current time. 74 * 75 * Upon every client access which results in a hit, the 76 * auth_time will be updated. 77 * 78 * If a client access determines that the auth_freshness 79 * indicates that the entry is STALE, then it will be 80 * refreshed. Note that this will explicitly reset 81 * auth_time. 82 * 83 * When the REFRESH successfully occurs, then the 84 * auth_freshness is updated. 85 * 86 * There are two ways for an entry to leave the cache: 87 * 88 * 1) Purged by an action on the export (remove or changed) 89 * 2) Memory backpressure from the kernel (check against NFSAUTH_CACHE_TRIM) 90 * 91 * For 2) we check the timeout value against auth_time. 92 */ 93 94 /* 95 * Number of seconds until we mark for refresh an auth cache entry. 96 */ 97 #define NFSAUTH_CACHE_REFRESH 600 98 99 /* 100 * Number of idle seconds until we yield to backpressure 101 * to trim a cache entry. 102 */ 103 #define NFSAUTH_CACHE_TRIM 3600 104 105 /* 106 * While we could encapuslate the exi_list inside the 107 * exi structure, we can't do that for the auth_list. 108 * So, to keep things looking clean, we keep them both 109 * in these external lists. 110 */ 111 typedef struct refreshq_exi_node { 112 struct exportinfo *ren_exi; 113 list_t ren_authlist; 114 list_node_t ren_node; 115 } refreshq_exi_node_t; 116 117 typedef struct refreshq_auth_node { 118 struct auth_cache *ran_auth; 119 list_node_t ran_node; 120 } refreshq_auth_node_t; 121 122 /* 123 * Used to manipulate things on the refreshq_queue. 124 * Note that the refresh thread will effectively 125 * pop a node off of the queue, at which point it 126 * will no longer need to hold the mutex. 127 */ 128 static kmutex_t refreshq_lock; 129 static list_t refreshq_queue; 130 static kcondvar_t refreshq_cv; 131 132 /* 133 * A list_t would be overkill. These are auth_cache 134 * entries which are no longer linked to an exi. 135 * It should be the case that all of their states 136 * are NFS_AUTH_INVALID. 137 * 138 * I.e., the only way to be put on this list is 139 * iff their state indicated that they had been placed 140 * on the refreshq_queue. 141 * 142 * Note that while there is no link from the exi or 143 * back to the exi, the exi can not go away until 144 * these entries are harvested. 145 */ 146 static struct auth_cache *refreshq_dead_entries; 147 148 /* 149 * If there is ever a problem with loading the 150 * module, then nfsauth_fini() needs to be called 151 * to remove state. In that event, since the 152 * refreshq thread has been started, they need to 153 * work together to get rid of state. 154 */ 155 typedef enum nfsauth_refreshq_thread_state { 156 REFRESHQ_THREAD_RUNNING, 157 REFRESHQ_THREAD_FINI_REQ, 158 REFRESHQ_THREAD_HALTED 159 } nfsauth_refreshq_thread_state_t; 160 161 nfsauth_refreshq_thread_state_t 162 refreshq_thread_state = REFRESHQ_THREAD_HALTED; 163 164 static void nfsauth_free_node(struct auth_cache *); 165 static void nfsauth_remove_dead_entry(struct auth_cache *); 166 static void nfsauth_refresh_thread(void); 167 168 /* 169 * mountd is a server-side only daemon. This will need to be 170 * revisited if the NFS server is ever made zones-aware. 171 */ 172 kmutex_t mountd_lock; 173 door_handle_t mountd_dh; 174 175 void 176 mountd_args(uint_t did) 177 { 178 mutex_enter(&mountd_lock); 179 if (mountd_dh) 180 door_ki_rele(mountd_dh); 181 mountd_dh = door_ki_lookup(did); 182 mutex_exit(&mountd_lock); 183 } 184 185 void 186 nfsauth_init(void) 187 { 188 /* 189 * mountd can be restarted by smf(5). We need to make sure 190 * the updated door handle will safely make it to mountd_dh 191 */ 192 mutex_init(&mountd_lock, NULL, MUTEX_DEFAULT, NULL); 193 194 mutex_init(&refreshq_lock, NULL, MUTEX_DEFAULT, NULL); 195 list_create(&refreshq_queue, sizeof (refreshq_exi_node_t), 196 offsetof(refreshq_exi_node_t, ren_node)); 197 refreshq_dead_entries = NULL; 198 199 cv_init(&refreshq_cv, NULL, CV_DEFAULT, NULL); 200 201 /* 202 * Allocate nfsauth cache handle 203 */ 204 exi_cache_handle = kmem_cache_create("exi_cache_handle", 205 sizeof (struct auth_cache), 0, NULL, NULL, 206 exi_cache_reclaim, NULL, NULL, 0); 207 208 refreshq_thread_state = REFRESHQ_THREAD_RUNNING; 209 (void) zthread_create(NULL, 0, nfsauth_refresh_thread, 210 NULL, 0, minclsyspri); 211 } 212 213 /* 214 * Finalization routine for nfsauth. It is important to call this routine 215 * before destroying the exported_lock. 216 */ 217 void 218 nfsauth_fini(void) 219 { 220 refreshq_exi_node_t *ren; 221 refreshq_auth_node_t *ran; 222 struct auth_cache *p; 223 struct auth_cache *auth_next; 224 225 /* 226 * Prevent the refreshq_thread from getting new 227 * work. 228 */ 229 mutex_enter(&refreshq_lock); 230 if (refreshq_thread_state != REFRESHQ_THREAD_HALTED) { 231 refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ; 232 cv_broadcast(&refreshq_cv); 233 234 /* 235 * Also, wait for nfsauth_refresh_thread() to exit. 236 */ 237 while (refreshq_thread_state != REFRESHQ_THREAD_HALTED) { 238 cv_wait(&refreshq_cv, &refreshq_lock); 239 } 240 } 241 242 /* 243 * Walk the exi_list and in turn, walk the 244 * auth_lists. 245 */ 246 while ((ren = list_remove_head(&refreshq_queue))) { 247 while ((ran = list_remove_head(&ren->ren_authlist))) { 248 kmem_free(ran, sizeof (refreshq_auth_node_t)); 249 } 250 251 list_destroy(&ren->ren_authlist); 252 exi_rele(ren->ren_exi); 253 kmem_free(ren, sizeof (refreshq_exi_node_t)); 254 } 255 256 /* 257 * Okay, now that the lists are deleted, we 258 * need to see if there are any dead entries 259 * to harvest. 260 */ 261 for (p = refreshq_dead_entries; p != NULL; p = auth_next) { 262 auth_next = p->auth_next; 263 nfsauth_free_node(p); 264 } 265 266 mutex_exit(&refreshq_lock); 267 268 list_destroy(&refreshq_queue); 269 270 cv_destroy(&refreshq_cv); 271 mutex_destroy(&refreshq_lock); 272 273 mutex_destroy(&mountd_lock); 274 275 /* 276 * Deallocate nfsauth cache handle 277 */ 278 kmem_cache_destroy(exi_cache_handle); 279 } 280 281 /* 282 * Convert the address in a netbuf to 283 * a hash index for the auth_cache table. 284 */ 285 static int 286 hash(struct netbuf *a) 287 { 288 int i, h = 0; 289 290 for (i = 0; i < a->len; i++) 291 h ^= a->buf[i]; 292 293 return (h & (AUTH_TABLESIZE - 1)); 294 } 295 296 /* 297 * Mask out the components of an 298 * address that do not identify 299 * a host. For socket addresses the 300 * masking gets rid of the port number. 301 */ 302 static void 303 addrmask(struct netbuf *addr, struct netbuf *mask) 304 { 305 int i; 306 307 for (i = 0; i < addr->len; i++) 308 addr->buf[i] &= mask->buf[i]; 309 } 310 311 /* 312 * nfsauth4_access is used for NFS V4 auth checking. Besides doing 313 * the common nfsauth_access(), it will check if the client can 314 * have a limited access to this vnode even if the security flavor 315 * used does not meet the policy. 316 */ 317 int 318 nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req) 319 { 320 int access; 321 322 access = nfsauth_access(exi, req); 323 324 /* 325 * There are cases that the server needs to allow the client 326 * to have a limited view. 327 * 328 * e.g. 329 * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw" 330 * /export/home is shared as "sec=sys,rw" 331 * 332 * When the client mounts /export with sec=sys, the client 333 * would get a limited view with RO access on /export to see 334 * "home" only because the client is allowed to access 335 * /export/home with auth_sys. 336 */ 337 if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { 338 /* 339 * Allow ro permission with LIMITED view if there is a 340 * sub-dir exported under vp. 341 */ 342 if (has_visible(exi, vp)) 343 return (NFSAUTH_LIMITED); 344 } 345 346 return (access); 347 } 348 349 static void 350 sys_log(const char *msg) 351 { 352 static time_t tstamp = 0; 353 time_t now; 354 355 /* 356 * msg is shown (at most) once per minute 357 */ 358 now = gethrestime_sec(); 359 if ((tstamp + 60) < now) { 360 tstamp = now; 361 cmn_err(CE_WARN, msg); 362 } 363 } 364 365 /* 366 * Callup to the mountd to get access information in the kernel. 367 */ 368 static bool_t 369 nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, 370 struct netbuf *addr, int *access) 371 { 372 varg_t varg = {0}; 373 nfsauth_res_t res = {0}; 374 XDR xdrs_a; 375 XDR xdrs_r; 376 size_t absz; 377 caddr_t abuf; 378 size_t rbsz = (size_t)(BYTES_PER_XDR_UNIT * 2); 379 char result[BYTES_PER_XDR_UNIT * 2] = {0}; 380 caddr_t rbuf = (caddr_t)&result; 381 int last = 0; 382 door_arg_t da; 383 door_info_t di; 384 door_handle_t dh; 385 uint_t ntries = 0; 386 387 /* 388 * No entry in the cache for this client/flavor 389 * so we need to call the nfsauth service in the 390 * mount daemon. 391 */ 392 retry: 393 mutex_enter(&mountd_lock); 394 dh = mountd_dh; 395 if (dh) 396 door_ki_hold(dh); 397 mutex_exit(&mountd_lock); 398 399 if (dh == NULL) { 400 /* 401 * The rendezvous point has not been established yet ! 402 * This could mean that either mountd(1m) has not yet 403 * been started or that _this_ routine nuked the door 404 * handle after receiving an EINTR for a REVOKED door. 405 * 406 * Returning NFSAUTH_DROP will cause the NFS client 407 * to retransmit the request, so let's try to be more 408 * rescillient and attempt for ntries before we bail. 409 */ 410 if (++ntries % NFSAUTH_DR_TRYCNT) { 411 delay(hz); 412 goto retry; 413 } 414 415 sys_log("nfsauth: mountd has not established door"); 416 *access = NFSAUTH_DROP; 417 return (FALSE); 418 } 419 420 ntries = 0; 421 varg.vers = V_PROTO; 422 varg.arg_u.arg.cmd = NFSAUTH_ACCESS; 423 varg.arg_u.arg.areq.req_client.n_len = addr->len; 424 varg.arg_u.arg.areq.req_client.n_bytes = addr->buf; 425 varg.arg_u.arg.areq.req_netid = req_netid; 426 varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; 427 varg.arg_u.arg.areq.req_flavor = flavor; 428 429 /* 430 * Setup the XDR stream for encoding the arguments. Notice that 431 * in addition to the args having variable fields (req_netid and 432 * req_path), the argument data structure is itself versioned, 433 * so we need to make sure we can size the arguments buffer 434 * appropriately to encode all the args. If we can't get sizing 435 * info _or_ properly encode the arguments, there's really no 436 * point in continuting, so we fail the request. 437 */ 438 DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); 439 if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) { 440 door_ki_rele(dh); 441 *access = NFSAUTH_DENIED; 442 return (FALSE); 443 } 444 445 abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); 446 xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE); 447 if (!xdr_varg(&xdrs_a, &varg)) { 448 door_ki_rele(dh); 449 goto fail; 450 } 451 XDR_DESTROY(&xdrs_a); 452 453 /* 454 * The result (nfsauth_res_t) is always two int's, so we don't 455 * have to dynamically size (or allocate) the results buffer. 456 * Now that we've got what we need, we prep the door arguments 457 * and place the call. 458 */ 459 da.data_ptr = (char *)abuf; 460 da.data_size = absz; 461 da.desc_ptr = NULL; 462 da.desc_num = 0; 463 da.rbuf = (char *)rbuf; 464 da.rsize = rbsz; 465 466 switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { 467 case 0: /* Success */ 468 if (da.data_ptr != da.rbuf && da.data_size == 0) { 469 /* 470 * The door_return that contained the data 471 * failed ! We're here because of the 2nd 472 * door_return (w/o data) such that we can 473 * get control of the thread (and exit 474 * gracefully). 475 */ 476 DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, 477 door_arg_t *, &da); 478 door_ki_rele(dh); 479 goto fail; 480 481 } else if (rbuf != da.rbuf) { 482 /* 483 * The only time this should be true 484 * is iff userland wanted to hand us 485 * a bigger response than what we 486 * expect; that should not happen 487 * (nfsauth_res_t is only 2 int's), 488 * but we check nevertheless. 489 */ 490 rbuf = da.rbuf; 491 rbsz = da.rsize; 492 493 } else if (rbsz > da.data_size) { 494 /* 495 * We were expecting two int's; but if 496 * userland fails in encoding the XDR 497 * stream, we detect that here, since 498 * the mountd forces down only one byte 499 * in such scenario. 500 */ 501 door_ki_rele(dh); 502 goto fail; 503 } 504 door_ki_rele(dh); 505 break; 506 507 case EAGAIN: 508 /* 509 * Server out of resources; back off for a bit 510 */ 511 door_ki_rele(dh); 512 kmem_free(abuf, absz); 513 delay(hz); 514 goto retry; 515 /* NOTREACHED */ 516 517 case EINTR: 518 if (!door_ki_info(dh, &di)) { 519 if (di.di_attributes & DOOR_REVOKED) { 520 /* 521 * The server barfed and revoked 522 * the (existing) door on us; we 523 * want to wait to give smf(5) a 524 * chance to restart mountd(1m) 525 * and establish a new door handle. 526 */ 527 mutex_enter(&mountd_lock); 528 if (dh == mountd_dh) 529 mountd_dh = NULL; 530 mutex_exit(&mountd_lock); 531 door_ki_rele(dh); 532 kmem_free(abuf, absz); 533 delay(hz); 534 goto retry; 535 } 536 /* 537 * If the door was _not_ revoked on us, 538 * then more than likely we took an INTR, 539 * so we need to fail the operation. 540 */ 541 door_ki_rele(dh); 542 goto fail; 543 } 544 /* 545 * The only failure that can occur from getting 546 * the door info is EINVAL, so we let the code 547 * below handle it. 548 */ 549 /* FALLTHROUGH */ 550 551 case EBADF: 552 case EINVAL: 553 default: 554 /* 555 * If we have a stale door handle, give smf a last 556 * chance to start it by sleeping for a little bit. 557 * If we're still hosed, we'll fail the call. 558 * 559 * Since we're going to reacquire the door handle 560 * upon the retry, we opt to sleep for a bit and 561 * _not_ to clear mountd_dh. If mountd restarted 562 * and was able to set mountd_dh, we should see 563 * the new instance; if not, we won't get caught 564 * up in the retry/DELAY loop. 565 */ 566 door_ki_rele(dh); 567 if (!last) { 568 delay(hz); 569 last++; 570 goto retry; 571 } 572 sys_log("nfsauth: stale mountd door handle"); 573 goto fail; 574 } 575 576 /* 577 * No door errors encountered; setup the XDR stream for decoding 578 * the results. If we fail to decode the results, we've got no 579 * other recourse than to fail the request. 580 */ 581 xdrmem_create(&xdrs_r, rbuf, rbsz, XDR_DECODE); 582 if (!xdr_nfsauth_res(&xdrs_r, &res)) 583 goto fail; 584 XDR_DESTROY(&xdrs_r); 585 586 DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res); 587 switch (res.stat) { 588 case NFSAUTH_DR_OKAY: 589 *access = res.ares.auth_perm; 590 kmem_free(abuf, absz); 591 break; 592 593 case NFSAUTH_DR_EFAIL: 594 case NFSAUTH_DR_DECERR: 595 case NFSAUTH_DR_BADCMD: 596 default: 597 fail: 598 *access = NFSAUTH_DENIED; 599 kmem_free(abuf, absz); 600 return (FALSE); 601 /* NOTREACHED */ 602 } 603 604 return (TRUE); 605 } 606 607 static void 608 nfsauth_refresh_thread(void) 609 { 610 refreshq_exi_node_t *ren; 611 refreshq_auth_node_t *ran; 612 613 struct exportinfo *exi; 614 struct auth_cache *p; 615 616 int access; 617 bool_t retrieval; 618 619 callb_cpr_t cprinfo; 620 621 CALLB_CPR_INIT(&cprinfo, &refreshq_lock, callb_generic_cpr, 622 "nfsauth_refresh"); 623 624 for (;;) { 625 mutex_enter(&refreshq_lock); 626 if (refreshq_thread_state != REFRESHQ_THREAD_RUNNING) { 627 /* Keep the hold on the lock! */ 628 break; 629 } 630 631 ren = list_remove_head(&refreshq_queue); 632 if (ren == NULL) { 633 CALLB_CPR_SAFE_BEGIN(&cprinfo); 634 cv_wait(&refreshq_cv, &refreshq_lock); 635 CALLB_CPR_SAFE_END(&cprinfo, &refreshq_lock); 636 mutex_exit(&refreshq_lock); 637 continue; 638 } 639 mutex_exit(&refreshq_lock); 640 641 exi = ren->ren_exi; 642 ASSERT(exi != NULL); 643 rw_enter(&exi->exi_cache_lock, RW_READER); 644 645 while ((ran = list_remove_head(&ren->ren_authlist))) { 646 /* 647 * We are shutting down. No need to refresh 648 * entries which are about to be nuked. 649 * 650 * So just throw them away until we are done 651 * with this exi node... 652 */ 653 if (refreshq_thread_state != 654 REFRESHQ_THREAD_RUNNING) { 655 kmem_free(ran, sizeof (refreshq_auth_node_t)); 656 continue; 657 } 658 659 p = ran->ran_auth; 660 ASSERT(p != NULL); 661 662 mutex_enter(&p->auth_lock); 663 664 /* 665 * Make sure the state is valid now that 666 * we have the lock. Note that once we 667 * change the state to NFS_AUTH_REFRESHING, 668 * no other thread will be able to work on 669 * this entry. 670 */ 671 if (p->auth_state != NFS_AUTH_STALE) { 672 /* 673 * Once it goes INVALID, it can not 674 * change state. 675 */ 676 if (p->auth_state == NFS_AUTH_INVALID) { 677 mutex_exit(&p->auth_lock); 678 nfsauth_remove_dead_entry(p); 679 } else 680 mutex_exit(&p->auth_lock); 681 682 kmem_free(ran, sizeof (refreshq_auth_node_t)); 683 continue; 684 } 685 686 p->auth_state = NFS_AUTH_REFRESHING; 687 mutex_exit(&p->auth_lock); 688 689 DTRACE_PROBE2(nfsauth__debug__cache__refresh, 690 struct exportinfo *, exi, 691 struct auth_cache *, p); 692 693 /* 694 * The first caching of the access rights 695 * is done with the netid pulled out of the 696 * request from the client. All subsequent 697 * users of the cache may or may not have 698 * the same netid. It doesn't matter. So 699 * when we refresh, we simply use the netid 700 * of the request which triggered the 701 * refresh attempt. 702 */ 703 ASSERT(p->auth_netid != NULL); 704 705 retrieval = nfsauth_retrieve(exi, p->auth_netid, 706 p->auth_flavor, &p->auth_addr, &access); 707 708 /* 709 * This can only be set in one other place 710 * and the state has to be NFS_AUTH_FRESH. 711 */ 712 kmem_free(p->auth_netid, strlen(p->auth_netid) + 1); 713 p->auth_netid = NULL; 714 715 /* 716 * We got an error, so do not reset the 717 * time. This will cause the next access 718 * check for the client to reschedule this 719 * node. 720 */ 721 if (retrieval == FALSE) { 722 mutex_enter(&p->auth_lock); 723 if (p->auth_state == NFS_AUTH_INVALID) { 724 mutex_exit(&p->auth_lock); 725 nfsauth_remove_dead_entry(p); 726 } else { 727 p->auth_state = NFS_AUTH_FRESH; 728 mutex_exit(&p->auth_lock); 729 } 730 731 kmem_free(ran, sizeof (refreshq_auth_node_t)); 732 continue; 733 } 734 735 mutex_enter(&p->auth_lock); 736 if (p->auth_state == NFS_AUTH_INVALID) { 737 mutex_exit(&p->auth_lock); 738 nfsauth_remove_dead_entry(p); 739 } else { 740 p->auth_access = access; 741 p->auth_freshness = gethrestime_sec(); 742 p->auth_state = NFS_AUTH_FRESH; 743 mutex_exit(&p->auth_lock); 744 } 745 746 kmem_free(ran, sizeof (refreshq_auth_node_t)); 747 } 748 749 rw_exit(&exi->exi_cache_lock); 750 751 list_destroy(&ren->ren_authlist); 752 exi_rele(ren->ren_exi); 753 kmem_free(ren, sizeof (refreshq_exi_node_t)); 754 } 755 756 refreshq_thread_state = REFRESHQ_THREAD_HALTED; 757 cv_broadcast(&refreshq_cv); 758 CALLB_CPR_EXIT(&cprinfo); 759 zthread_exit(); 760 } 761 762 /* 763 * Get the access information from the cache or callup to the mountd 764 * to get and cache the access information in the kernel. 765 */ 766 int 767 nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor) 768 { 769 struct netbuf *taddrmask; 770 struct netbuf addr; 771 struct netbuf *claddr; 772 struct auth_cache **head; 773 struct auth_cache *p; 774 int access; 775 time_t refresh; 776 777 refreshq_exi_node_t *ren; 778 refreshq_auth_node_t *ran; 779 780 /* 781 * Now check whether this client already 782 * has an entry for this flavor in the cache 783 * for this export. 784 * Get the caller's address, mask off the 785 * parts of the address that do not identify 786 * the host (port number, etc), and then hash 787 * it to find the chain of cache entries. 788 */ 789 790 claddr = svc_getrpccaller(req->rq_xprt); 791 addr = *claddr; 792 addr.buf = kmem_alloc(addr.len, KM_SLEEP); 793 bcopy(claddr->buf, addr.buf, claddr->len); 794 SVC_GETADDRMASK(req->rq_xprt, SVC_TATTR_ADDRMASK, (void **)&taddrmask); 795 ASSERT(taddrmask != NULL); 796 if (taddrmask) 797 addrmask(&addr, taddrmask); 798 799 rw_enter(&exi->exi_cache_lock, RW_READER); 800 head = &exi->exi_cache[hash(&addr)]; 801 for (p = *head; p; p = p->auth_next) { 802 if (EQADDR(&addr, &p->auth_addr) && flavor == p->auth_flavor) 803 break; 804 } 805 806 if (p != NULL) { 807 nfsauth_cache_hit++; 808 809 refresh = gethrestime_sec() - p->auth_freshness; 810 DTRACE_PROBE2(nfsauth__debug__cache__hit, 811 int, nfsauth_cache_hit, 812 time_t, refresh); 813 814 mutex_enter(&p->auth_lock); 815 if ((refresh > NFSAUTH_CACHE_REFRESH) && 816 p->auth_state == NFS_AUTH_FRESH) { 817 p->auth_state = NFS_AUTH_STALE; 818 mutex_exit(&p->auth_lock); 819 820 ASSERT(p->auth_netid == NULL); 821 p->auth_netid = 822 strdup(svc_getnetid(req->rq_xprt)); 823 824 nfsauth_cache_refresh++; 825 826 DTRACE_PROBE3(nfsauth__debug__cache__stale, 827 struct exportinfo *, exi, 828 struct auth_cache *, p, 829 int, nfsauth_cache_refresh); 830 831 ran = kmem_alloc(sizeof (refreshq_auth_node_t), 832 KM_SLEEP); 833 ran->ran_auth = p; 834 835 mutex_enter(&refreshq_lock); 836 /* 837 * We should not add a work queue 838 * item if the thread is not 839 * accepting them. 840 */ 841 if (refreshq_thread_state == REFRESHQ_THREAD_RUNNING) { 842 /* 843 * Is there an existing exi_list? 844 */ 845 for (ren = list_head(&refreshq_queue); 846 ren != NULL; 847 ren = list_next(&refreshq_queue, ren)) { 848 if (ren->ren_exi == exi) { 849 list_insert_tail( 850 &ren->ren_authlist, ran); 851 break; 852 } 853 } 854 855 if (ren == NULL) { 856 ren = kmem_alloc( 857 sizeof (refreshq_exi_node_t), 858 KM_SLEEP); 859 860 exi_hold(exi); 861 ren->ren_exi = exi; 862 863 list_create(&ren->ren_authlist, 864 sizeof (refreshq_auth_node_t), 865 offsetof(refreshq_auth_node_t, 866 ran_node)); 867 868 list_insert_tail(&ren->ren_authlist, 869 ran); 870 list_insert_tail(&refreshq_queue, ren); 871 } 872 873 cv_broadcast(&refreshq_cv); 874 } else { 875 kmem_free(ran, sizeof (refreshq_auth_node_t)); 876 } 877 878 mutex_exit(&refreshq_lock); 879 } else { 880 mutex_exit(&p->auth_lock); 881 } 882 883 access = p->auth_access; 884 p->auth_time = gethrestime_sec(); 885 886 rw_exit(&exi->exi_cache_lock); 887 kmem_free(addr.buf, addr.len); 888 889 return (access); 890 } 891 892 rw_exit(&exi->exi_cache_lock); 893 894 nfsauth_cache_miss++; 895 896 if (!nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, 897 &addr, &access)) { 898 kmem_free(addr.buf, addr.len); 899 return (access); 900 } 901 902 /* 903 * Now cache the result on the cache chain 904 * for this export (if there's enough memory) 905 */ 906 p = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP); 907 if (p != NULL) { 908 p->auth_addr = addr; 909 p->auth_flavor = flavor; 910 p->auth_access = access; 911 p->auth_time = p->auth_freshness = gethrestime_sec(); 912 p->auth_state = NFS_AUTH_FRESH; 913 p->auth_netid = NULL; 914 mutex_init(&p->auth_lock, NULL, MUTEX_DEFAULT, NULL); 915 916 rw_enter(&exi->exi_cache_lock, RW_WRITER); 917 p->auth_next = *head; 918 *head = p; 919 rw_exit(&exi->exi_cache_lock); 920 } else { 921 kmem_free(addr.buf, addr.len); 922 } 923 924 return (access); 925 } 926 927 /* 928 * Check if the requesting client has access to the filesystem with 929 * a given nfs flavor number which is an explicitly shared flavor. 930 */ 931 int 932 nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, 933 int flavor, int perm) 934 { 935 int access; 936 937 if (! (perm & M_4SEC_EXPORTED)) { 938 return (NFSAUTH_DENIED); 939 } 940 941 /* 942 * Optimize if there are no lists 943 */ 944 if ((perm & (M_ROOT|M_NONE)) == 0) { 945 perm &= ~M_4SEC_EXPORTED; 946 if (perm == M_RO) 947 return (NFSAUTH_RO); 948 if (perm == M_RW) 949 return (NFSAUTH_RW); 950 } 951 952 access = nfsauth_cache_get(exi, req, flavor); 953 954 return (access); 955 } 956 957 int 958 nfsauth_access(struct exportinfo *exi, struct svc_req *req) 959 { 960 int access, mapaccess; 961 struct secinfo *sp; 962 int i, flavor, perm; 963 int authnone_entry = -1; 964 965 /* 966 * Get the nfs flavor number from xprt. 967 */ 968 flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 969 970 /* 971 * First check the access restrictions on the filesystem. If 972 * there are no lists associated with this flavor then there's no 973 * need to make an expensive call to the nfsauth service or to 974 * cache anything. 975 */ 976 977 sp = exi->exi_export.ex_secinfo; 978 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 979 if (flavor != sp[i].s_secinfo.sc_nfsnum) { 980 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 981 authnone_entry = i; 982 continue; 983 } 984 break; 985 } 986 987 mapaccess = 0; 988 989 if (i >= exi->exi_export.ex_seccnt) { 990 /* 991 * Flavor not found, but use AUTH_NONE if it exists 992 */ 993 if (authnone_entry == -1) 994 return (NFSAUTH_DENIED); 995 flavor = AUTH_NONE; 996 mapaccess = NFSAUTH_MAPNONE; 997 i = authnone_entry; 998 } 999 1000 /* 1001 * If the flavor is in the ex_secinfo list, but not an explicitly 1002 * shared flavor by the user, it is a result of the nfsv4 server 1003 * namespace setup. We will grant an RO permission similar for 1004 * a pseudo node except that this node is a shared one. 1005 * 1006 * e.g. flavor in (flavor) indicates that it is not explictly 1007 * shared by the user: 1008 * 1009 * / (sys, krb5) 1010 * | 1011 * export #share -o sec=sys (krb5) 1012 * | 1013 * secure #share -o sec=krb5 1014 * 1015 * In this case, when a krb5 request coming in to access 1016 * /export, RO permission is granted. 1017 */ 1018 if (!(sp[i].s_flags & M_4SEC_EXPORTED)) 1019 return (mapaccess | NFSAUTH_RO); 1020 1021 /* 1022 * Optimize if there are no lists 1023 */ 1024 perm = sp[i].s_flags; 1025 if ((perm & (M_ROOT|M_NONE)) == 0) { 1026 perm &= ~M_4SEC_EXPORTED; 1027 if (perm == M_RO) 1028 return (mapaccess | NFSAUTH_RO); 1029 if (perm == M_RW) 1030 return (mapaccess | NFSAUTH_RW); 1031 } 1032 1033 access = nfsauth_cache_get(exi, req, flavor); 1034 1035 /* 1036 * Client's security flavor doesn't match with "ro" or 1037 * "rw" list. Try again using AUTH_NONE if present. 1038 */ 1039 if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) { 1040 /* 1041 * Have we already encountered AUTH_NONE ? 1042 */ 1043 if (authnone_entry != -1) { 1044 mapaccess = NFSAUTH_MAPNONE; 1045 access = nfsauth_cache_get(exi, req, AUTH_NONE); 1046 } else { 1047 /* 1048 * Check for AUTH_NONE presence. 1049 */ 1050 for (; i < exi->exi_export.ex_seccnt; i++) { 1051 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 1052 mapaccess = NFSAUTH_MAPNONE; 1053 access = nfsauth_cache_get(exi, req, 1054 AUTH_NONE); 1055 break; 1056 } 1057 } 1058 } 1059 } 1060 1061 if (access & NFSAUTH_DENIED) 1062 access = NFSAUTH_DENIED; 1063 1064 return (access | mapaccess); 1065 } 1066 1067 static void 1068 nfsauth_free_node(struct auth_cache *p) 1069 { 1070 if (p->auth_netid != NULL) 1071 kmem_free(p->auth_netid, strlen(p->auth_netid) + 1); 1072 kmem_free(p->auth_addr.buf, p->auth_addr.len); 1073 mutex_destroy(&p->auth_lock); 1074 kmem_cache_free(exi_cache_handle, (void *)p); 1075 } 1076 1077 /* 1078 * Remove the dead entry from the refreshq_dead_entries 1079 * list. 1080 */ 1081 static void 1082 nfsauth_remove_dead_entry(struct auth_cache *dead) 1083 { 1084 struct auth_cache *p; 1085 struct auth_cache *prev; 1086 struct auth_cache *next; 1087 1088 mutex_enter(&refreshq_lock); 1089 prev = NULL; 1090 for (p = refreshq_dead_entries; p != NULL; p = next) { 1091 next = p->auth_next; 1092 1093 if (p == dead) { 1094 if (prev == NULL) 1095 refreshq_dead_entries = next; 1096 else 1097 prev->auth_next = next; 1098 1099 nfsauth_free_node(dead); 1100 break; 1101 } 1102 1103 prev = p; 1104 } 1105 mutex_exit(&refreshq_lock); 1106 } 1107 1108 /* 1109 * Free the nfsauth cache for a given export 1110 */ 1111 void 1112 nfsauth_cache_free(struct exportinfo *exi) 1113 { 1114 int i; 1115 struct auth_cache *p, *next; 1116 1117 for (i = 0; i < AUTH_TABLESIZE; i++) { 1118 for (p = exi->exi_cache[i]; p; p = next) { 1119 next = p->auth_next; 1120 1121 /* 1122 * The only way we got here 1123 * was with an exi_rele, which 1124 * means that no auth cache entry 1125 * is being refreshed. 1126 */ 1127 nfsauth_free_node(p); 1128 } 1129 } 1130 } 1131 1132 /* 1133 * Called by the kernel memory allocator when 1134 * memory is low. Free unused cache entries. 1135 * If that's not enough, the VM system will 1136 * call again for some more. 1137 */ 1138 /*ARGSUSED*/ 1139 void 1140 exi_cache_reclaim(void *cdrarg) 1141 { 1142 int i; 1143 struct exportinfo *exi; 1144 1145 rw_enter(&exported_lock, RW_READER); 1146 1147 for (i = 0; i < EXPTABLESIZE; i++) { 1148 for (exi = exptable[i]; exi; exi = exi->exi_hash) { 1149 exi_cache_trim(exi); 1150 } 1151 } 1152 nfsauth_cache_reclaim++; 1153 1154 rw_exit(&exported_lock); 1155 } 1156 1157 void 1158 exi_cache_trim(struct exportinfo *exi) 1159 { 1160 struct auth_cache *p; 1161 struct auth_cache *prev, *next; 1162 int i; 1163 time_t stale_time; 1164 1165 stale_time = gethrestime_sec() - NFSAUTH_CACHE_TRIM; 1166 1167 rw_enter(&exi->exi_cache_lock, RW_WRITER); 1168 1169 for (i = 0; i < AUTH_TABLESIZE; i++) { 1170 1171 /* 1172 * Free entries that have not been 1173 * used for NFSAUTH_CACHE_TRIM seconds. 1174 */ 1175 prev = NULL; 1176 for (p = exi->exi_cache[i]; p; p = next) { 1177 next = p->auth_next; 1178 if (p->auth_time > stale_time) { 1179 prev = p; 1180 continue; 1181 } 1182 1183 mutex_enter(&p->auth_lock); 1184 DTRACE_PROBE1(nfsauth__debug__trim__state, 1185 auth_state_t, p->auth_state); 1186 1187 if (p->auth_state != NFS_AUTH_FRESH) { 1188 p->auth_state = NFS_AUTH_INVALID; 1189 mutex_exit(&p->auth_lock); 1190 1191 mutex_enter(&refreshq_lock); 1192 p->auth_next = refreshq_dead_entries; 1193 refreshq_dead_entries = p; 1194 mutex_exit(&refreshq_lock); 1195 } else { 1196 mutex_exit(&p->auth_lock); 1197 nfsauth_free_node(p); 1198 } 1199 1200 if (prev == NULL) 1201 exi->exi_cache[i] = next; 1202 else 1203 prev->auth_next = next; 1204 } 1205 } 1206 1207 rw_exit(&exi->exi_cache_lock); 1208 } 1209