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