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 addr; 770 struct netbuf *claddr; 771 struct auth_cache **head; 772 struct auth_cache *p; 773 int access; 774 time_t refresh; 775 776 refreshq_exi_node_t *ren; 777 refreshq_auth_node_t *ran; 778 779 /* 780 * Now check whether this client already 781 * has an entry for this flavor in the cache 782 * for this export. 783 * Get the caller's address, mask off the 784 * parts of the address that do not identify 785 * the host (port number, etc), and then hash 786 * it to find the chain of cache entries. 787 */ 788 789 claddr = svc_getrpccaller(req->rq_xprt); 790 addr = *claddr; 791 addr.buf = kmem_alloc(addr.len, KM_SLEEP); 792 bcopy(claddr->buf, addr.buf, claddr->len); 793 addrmask(&addr, svc_getaddrmask(req->rq_xprt)); 794 795 rw_enter(&exi->exi_cache_lock, RW_READER); 796 head = &exi->exi_cache[hash(&addr)]; 797 for (p = *head; p; p = p->auth_next) { 798 if (EQADDR(&addr, &p->auth_addr) && flavor == p->auth_flavor) 799 break; 800 } 801 802 if (p != NULL) { 803 nfsauth_cache_hit++; 804 805 refresh = gethrestime_sec() - p->auth_freshness; 806 DTRACE_PROBE2(nfsauth__debug__cache__hit, 807 int, nfsauth_cache_hit, 808 time_t, refresh); 809 810 mutex_enter(&p->auth_lock); 811 if ((refresh > NFSAUTH_CACHE_REFRESH) && 812 p->auth_state == NFS_AUTH_FRESH) { 813 p->auth_state = NFS_AUTH_STALE; 814 mutex_exit(&p->auth_lock); 815 816 ASSERT(p->auth_netid == NULL); 817 p->auth_netid = 818 strdup(svc_getnetid(req->rq_xprt)); 819 820 nfsauth_cache_refresh++; 821 822 DTRACE_PROBE3(nfsauth__debug__cache__stale, 823 struct exportinfo *, exi, 824 struct auth_cache *, p, 825 int, nfsauth_cache_refresh); 826 827 ran = kmem_alloc(sizeof (refreshq_auth_node_t), 828 KM_SLEEP); 829 ran->ran_auth = p; 830 831 mutex_enter(&refreshq_lock); 832 /* 833 * We should not add a work queue 834 * item if the thread is not 835 * accepting them. 836 */ 837 if (refreshq_thread_state == REFRESHQ_THREAD_RUNNING) { 838 /* 839 * Is there an existing exi_list? 840 */ 841 for (ren = list_head(&refreshq_queue); 842 ren != NULL; 843 ren = list_next(&refreshq_queue, ren)) { 844 if (ren->ren_exi == exi) { 845 list_insert_tail( 846 &ren->ren_authlist, ran); 847 break; 848 } 849 } 850 851 if (ren == NULL) { 852 ren = kmem_alloc( 853 sizeof (refreshq_exi_node_t), 854 KM_SLEEP); 855 856 exi_hold(exi); 857 ren->ren_exi = exi; 858 859 list_create(&ren->ren_authlist, 860 sizeof (refreshq_auth_node_t), 861 offsetof(refreshq_auth_node_t, 862 ran_node)); 863 864 list_insert_tail(&ren->ren_authlist, 865 ran); 866 list_insert_tail(&refreshq_queue, ren); 867 } 868 869 cv_broadcast(&refreshq_cv); 870 } else { 871 kmem_free(ran, sizeof (refreshq_auth_node_t)); 872 } 873 874 mutex_exit(&refreshq_lock); 875 } else { 876 mutex_exit(&p->auth_lock); 877 } 878 879 access = p->auth_access; 880 p->auth_time = gethrestime_sec(); 881 882 rw_exit(&exi->exi_cache_lock); 883 kmem_free(addr.buf, addr.len); 884 885 return (access); 886 } 887 888 rw_exit(&exi->exi_cache_lock); 889 890 nfsauth_cache_miss++; 891 892 if (!nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, 893 &addr, &access)) { 894 kmem_free(addr.buf, addr.len); 895 return (access); 896 } 897 898 /* 899 * Now cache the result on the cache chain 900 * for this export (if there's enough memory) 901 */ 902 p = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP); 903 if (p != NULL) { 904 p->auth_addr = addr; 905 p->auth_flavor = flavor; 906 p->auth_access = access; 907 p->auth_time = p->auth_freshness = gethrestime_sec(); 908 p->auth_state = NFS_AUTH_FRESH; 909 p->auth_netid = NULL; 910 mutex_init(&p->auth_lock, NULL, MUTEX_DEFAULT, NULL); 911 912 rw_enter(&exi->exi_cache_lock, RW_WRITER); 913 p->auth_next = *head; 914 *head = p; 915 rw_exit(&exi->exi_cache_lock); 916 } else { 917 kmem_free(addr.buf, addr.len); 918 } 919 920 return (access); 921 } 922 923 /* 924 * Check if the requesting client has access to the filesystem with 925 * a given nfs flavor number which is an explicitly shared flavor. 926 */ 927 int 928 nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, 929 int flavor, int perm) 930 { 931 int access; 932 933 if (! (perm & M_4SEC_EXPORTED)) { 934 return (NFSAUTH_DENIED); 935 } 936 937 /* 938 * Optimize if there are no lists 939 */ 940 if ((perm & (M_ROOT|M_NONE)) == 0) { 941 perm &= ~M_4SEC_EXPORTED; 942 if (perm == M_RO) 943 return (NFSAUTH_RO); 944 if (perm == M_RW) 945 return (NFSAUTH_RW); 946 } 947 948 access = nfsauth_cache_get(exi, req, flavor); 949 950 return (access); 951 } 952 953 int 954 nfsauth_access(struct exportinfo *exi, struct svc_req *req) 955 { 956 int access, mapaccess; 957 struct secinfo *sp; 958 int i, flavor, perm; 959 int authnone_entry = -1; 960 961 /* 962 * Get the nfs flavor number from xprt. 963 */ 964 flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 965 966 /* 967 * First check the access restrictions on the filesystem. If 968 * there are no lists associated with this flavor then there's no 969 * need to make an expensive call to the nfsauth service or to 970 * cache anything. 971 */ 972 973 sp = exi->exi_export.ex_secinfo; 974 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 975 if (flavor != sp[i].s_secinfo.sc_nfsnum) { 976 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 977 authnone_entry = i; 978 continue; 979 } 980 break; 981 } 982 983 mapaccess = 0; 984 985 if (i >= exi->exi_export.ex_seccnt) { 986 /* 987 * Flavor not found, but use AUTH_NONE if it exists 988 */ 989 if (authnone_entry == -1) 990 return (NFSAUTH_DENIED); 991 flavor = AUTH_NONE; 992 mapaccess = NFSAUTH_MAPNONE; 993 i = authnone_entry; 994 } 995 996 /* 997 * If the flavor is in the ex_secinfo list, but not an explicitly 998 * shared flavor by the user, it is a result of the nfsv4 server 999 * namespace setup. We will grant an RO permission similar for 1000 * a pseudo node except that this node is a shared one. 1001 * 1002 * e.g. flavor in (flavor) indicates that it is not explictly 1003 * shared by the user: 1004 * 1005 * / (sys, krb5) 1006 * | 1007 * export #share -o sec=sys (krb5) 1008 * | 1009 * secure #share -o sec=krb5 1010 * 1011 * In this case, when a krb5 request coming in to access 1012 * /export, RO permission is granted. 1013 */ 1014 if (!(sp[i].s_flags & M_4SEC_EXPORTED)) 1015 return (mapaccess | NFSAUTH_RO); 1016 1017 /* 1018 * Optimize if there are no lists 1019 */ 1020 perm = sp[i].s_flags; 1021 if ((perm & (M_ROOT|M_NONE)) == 0) { 1022 perm &= ~M_4SEC_EXPORTED; 1023 if (perm == M_RO) 1024 return (mapaccess | NFSAUTH_RO); 1025 if (perm == M_RW) 1026 return (mapaccess | NFSAUTH_RW); 1027 } 1028 1029 access = nfsauth_cache_get(exi, req, flavor); 1030 1031 /* 1032 * Client's security flavor doesn't match with "ro" or 1033 * "rw" list. Try again using AUTH_NONE if present. 1034 */ 1035 if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) { 1036 /* 1037 * Have we already encountered AUTH_NONE ? 1038 */ 1039 if (authnone_entry != -1) { 1040 mapaccess = NFSAUTH_MAPNONE; 1041 access = nfsauth_cache_get(exi, req, AUTH_NONE); 1042 } else { 1043 /* 1044 * Check for AUTH_NONE presence. 1045 */ 1046 for (; i < exi->exi_export.ex_seccnt; i++) { 1047 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 1048 mapaccess = NFSAUTH_MAPNONE; 1049 access = nfsauth_cache_get(exi, req, 1050 AUTH_NONE); 1051 break; 1052 } 1053 } 1054 } 1055 } 1056 1057 if (access & NFSAUTH_DENIED) 1058 access = NFSAUTH_DENIED; 1059 1060 return (access | mapaccess); 1061 } 1062 1063 static void 1064 nfsauth_free_node(struct auth_cache *p) 1065 { 1066 if (p->auth_netid != NULL) 1067 kmem_free(p->auth_netid, strlen(p->auth_netid) + 1); 1068 kmem_free(p->auth_addr.buf, p->auth_addr.len); 1069 mutex_destroy(&p->auth_lock); 1070 kmem_cache_free(exi_cache_handle, (void *)p); 1071 } 1072 1073 /* 1074 * Remove the dead entry from the refreshq_dead_entries 1075 * list. 1076 */ 1077 static void 1078 nfsauth_remove_dead_entry(struct auth_cache *dead) 1079 { 1080 struct auth_cache *p; 1081 struct auth_cache *prev; 1082 struct auth_cache *next; 1083 1084 mutex_enter(&refreshq_lock); 1085 prev = NULL; 1086 for (p = refreshq_dead_entries; p != NULL; p = next) { 1087 next = p->auth_next; 1088 1089 if (p == dead) { 1090 if (prev == NULL) 1091 refreshq_dead_entries = next; 1092 else 1093 prev->auth_next = next; 1094 1095 nfsauth_free_node(dead); 1096 break; 1097 } 1098 1099 prev = p; 1100 } 1101 mutex_exit(&refreshq_lock); 1102 } 1103 1104 /* 1105 * Free the nfsauth cache for a given export 1106 */ 1107 void 1108 nfsauth_cache_free(struct exportinfo *exi) 1109 { 1110 int i; 1111 struct auth_cache *p, *next; 1112 1113 for (i = 0; i < AUTH_TABLESIZE; i++) { 1114 for (p = exi->exi_cache[i]; p; p = next) { 1115 next = p->auth_next; 1116 1117 /* 1118 * The only way we got here 1119 * was with an exi_rele, which 1120 * means that no auth cache entry 1121 * is being refreshed. 1122 */ 1123 nfsauth_free_node(p); 1124 } 1125 } 1126 } 1127 1128 /* 1129 * Called by the kernel memory allocator when 1130 * memory is low. Free unused cache entries. 1131 * If that's not enough, the VM system will 1132 * call again for some more. 1133 */ 1134 /*ARGSUSED*/ 1135 void 1136 exi_cache_reclaim(void *cdrarg) 1137 { 1138 int i; 1139 struct exportinfo *exi; 1140 1141 rw_enter(&exported_lock, RW_READER); 1142 1143 for (i = 0; i < EXPTABLESIZE; i++) { 1144 for (exi = exptable[i]; exi; exi = exi->exi_hash) { 1145 exi_cache_trim(exi); 1146 } 1147 } 1148 nfsauth_cache_reclaim++; 1149 1150 rw_exit(&exported_lock); 1151 } 1152 1153 void 1154 exi_cache_trim(struct exportinfo *exi) 1155 { 1156 struct auth_cache *p; 1157 struct auth_cache *prev, *next; 1158 int i; 1159 time_t stale_time; 1160 1161 stale_time = gethrestime_sec() - NFSAUTH_CACHE_TRIM; 1162 1163 rw_enter(&exi->exi_cache_lock, RW_WRITER); 1164 1165 for (i = 0; i < AUTH_TABLESIZE; i++) { 1166 1167 /* 1168 * Free entries that have not been 1169 * used for NFSAUTH_CACHE_TRIM seconds. 1170 */ 1171 prev = NULL; 1172 for (p = exi->exi_cache[i]; p; p = next) { 1173 next = p->auth_next; 1174 if (p->auth_time > stale_time) { 1175 prev = p; 1176 continue; 1177 } 1178 1179 mutex_enter(&p->auth_lock); 1180 DTRACE_PROBE1(nfsauth__debug__trim__state, 1181 auth_state_t, p->auth_state); 1182 1183 if (p->auth_state != NFS_AUTH_FRESH) { 1184 p->auth_state = NFS_AUTH_INVALID; 1185 mutex_exit(&p->auth_lock); 1186 1187 mutex_enter(&refreshq_lock); 1188 p->auth_next = refreshq_dead_entries; 1189 refreshq_dead_entries = p; 1190 mutex_exit(&refreshq_lock); 1191 } else { 1192 mutex_exit(&p->auth_lock); 1193 nfsauth_free_node(p); 1194 } 1195 1196 if (prev == NULL) 1197 exi->exi_cache[i] = next; 1198 else 1199 prev->auth_next = next; 1200 } 1201 } 1202 1203 rw_exit(&exi->exi_cache_lock); 1204 } 1205