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 2006 Sun Microsystems, Inc. 23 * All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/systm.h> 32 #include <sys/cred.h> 33 #include <sys/proc.h> 34 #include <sys/user.h> 35 #include <sys/buf.h> 36 #include <sys/vfs.h> 37 #include <sys/vnode.h> 38 #include <sys/pathname.h> 39 #include <sys/uio.h> 40 #include <sys/file.h> 41 #include <sys/stat.h> 42 #include <sys/errno.h> 43 #include <sys/socket.h> 44 #include <sys/sysmacros.h> 45 #include <sys/siginfo.h> 46 #include <sys/tiuser.h> 47 #include <sys/statvfs.h> 48 #include <sys/t_kuser.h> 49 #include <sys/kmem.h> 50 #include <sys/kstat.h> 51 #include <sys/acl.h> 52 #include <sys/dirent.h> 53 #include <sys/cmn_err.h> 54 #include <sys/debug.h> 55 #include <sys/unistd.h> 56 #include <sys/vtrace.h> 57 #include <sys/mode.h> 58 59 #include <rpc/types.h> 60 #include <rpc/auth.h> 61 #include <rpc/svc.h> 62 #include <rpc/xdr.h> 63 64 #include <nfs/nfs.h> 65 #include <nfs/export.h> 66 #include <nfs/nfssys.h> 67 #include <nfs/nfs_clnt.h> 68 #include <nfs/nfs_acl.h> 69 70 #include <fs/fs_subr.h> 71 72 /* 73 * These are the interface routines for the server side of the 74 * NFS ACL server. See the NFS ACL protocol specification 75 * for a description of this interface. 76 */ 77 78 /* ARGSUSED */ 79 void 80 acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi, 81 struct svc_req *req, cred_t *cr) 82 { 83 int error; 84 vnode_t *vp; 85 vattr_t va; 86 87 vp = nfs_fhtovp(&args->fh, exi); 88 if (vp == NULL) { 89 resp->status = NFSERR_STALE; 90 return; 91 } 92 93 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 94 95 resp->resok.acl.vsa_mask = args->mask; 96 97 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr); 98 99 if (error == ENOSYS) { 100 /* 101 * If the underlying file system doesn't support 102 * aclent_t type acls, fabricate an acl. This is 103 * required in order to to support existing clients 104 * that require the call to VOP_GETSECATTR to 105 * succeed while making the assumption that all 106 * file systems support aclent_t type acls. This 107 * causes problems for servers exporting ZFS file 108 * systems because ZFS supports ace_t type acls, 109 * and fails (with ENOSYS) when asked for aclent_t 110 * type acls. 111 * 112 * Note: if the fs_fab_acl() fails, we have other problems. 113 * This error should be returned to the caller. 114 */ 115 error = fs_fab_acl(vp, &resp->resok.acl, 0, cr); 116 } 117 118 if (error) { 119 VN_RELE(vp); 120 resp->status = puterrno(error); 121 return; 122 } 123 124 va.va_mask = AT_ALL; 125 error = rfs4_delegated_getattr(vp, &va, 0, cr); 126 127 VN_RELE(vp); 128 129 /* check for overflowed values */ 130 if (!error) { 131 error = vattr_to_nattr(&va, &resp->resok.attr); 132 } 133 if (error) { 134 resp->status = puterrno(error); 135 if (resp->resok.acl.vsa_aclcnt > 0 && 136 resp->resok.acl.vsa_aclentp != NULL) { 137 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 138 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 139 } 140 if (resp->resok.acl.vsa_dfaclcnt > 0 && 141 resp->resok.acl.vsa_dfaclentp != NULL) { 142 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 143 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 144 } 145 return; 146 } 147 148 resp->status = NFS_OK; 149 if (!(args->mask & NA_ACL)) { 150 if (resp->resok.acl.vsa_aclcnt > 0 && 151 resp->resok.acl.vsa_aclentp != NULL) { 152 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 153 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 154 } 155 resp->resok.acl.vsa_aclentp = NULL; 156 } 157 if (!(args->mask & NA_DFACL)) { 158 if (resp->resok.acl.vsa_dfaclcnt > 0 && 159 resp->resok.acl.vsa_dfaclentp != NULL) { 160 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 161 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 162 } 163 resp->resok.acl.vsa_dfaclentp = NULL; 164 } 165 } 166 167 void * 168 acl2_getacl_getfh(GETACL2args *args) 169 { 170 171 return (&args->fh); 172 } 173 174 void 175 acl2_getacl_free(GETACL2res *resp) 176 { 177 178 if (resp->status == NFS_OK) { 179 if (resp->resok.acl.vsa_aclcnt > 0 && 180 resp->resok.acl.vsa_aclentp != NULL) { 181 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 182 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 183 } 184 if (resp->resok.acl.vsa_dfaclcnt > 0 && 185 resp->resok.acl.vsa_dfaclentp != NULL) { 186 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 187 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 188 } 189 } 190 } 191 192 /* ARGSUSED */ 193 void 194 acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi, 195 struct svc_req *req, cred_t *cr) 196 { 197 int error; 198 vnode_t *vp; 199 vattr_t va; 200 201 vp = nfs_fhtovp(&args->fh, exi); 202 if (vp == NULL) { 203 resp->status = NFSERR_STALE; 204 return; 205 } 206 207 if (rdonly(exi, req) || vn_is_readonly(vp)) { 208 VN_RELE(vp); 209 resp->status = NFSERR_ROFS; 210 return; 211 } 212 213 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 214 error = VOP_SETSECATTR(vp, &args->acl, 0, cr); 215 if (error) { 216 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 217 VN_RELE(vp); 218 resp->status = puterrno(error); 219 return; 220 } 221 222 va.va_mask = AT_ALL; 223 error = rfs4_delegated_getattr(vp, &va, 0, cr); 224 225 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 226 VN_RELE(vp); 227 228 /* check for overflowed values */ 229 if (!error) { 230 error = vattr_to_nattr(&va, &resp->resok.attr); 231 } 232 if (error) { 233 resp->status = puterrno(error); 234 return; 235 } 236 237 resp->status = NFS_OK; 238 } 239 240 void * 241 acl2_setacl_getfh(SETACL2args *args) 242 { 243 244 return (&args->fh); 245 } 246 247 /* ARGSUSED */ 248 void 249 acl2_getattr(GETATTR2args *args, GETATTR2res *resp, struct exportinfo *exi, 250 struct svc_req *req, cred_t *cr) 251 { 252 int error; 253 vnode_t *vp; 254 vattr_t va; 255 256 vp = nfs_fhtovp(&args->fh, exi); 257 if (vp == NULL) { 258 resp->status = NFSERR_STALE; 259 return; 260 } 261 262 va.va_mask = AT_ALL; 263 error = rfs4_delegated_getattr(vp, &va, 0, cr); 264 265 VN_RELE(vp); 266 267 /* check for overflowed values */ 268 if (!error) { 269 error = vattr_to_nattr(&va, &resp->resok.attr); 270 } 271 if (error) { 272 resp->status = puterrno(error); 273 return; 274 } 275 276 resp->status = NFS_OK; 277 } 278 279 void * 280 acl2_getattr_getfh(GETATTR2args *args) 281 { 282 283 return (&args->fh); 284 } 285 286 /* ARGSUSED */ 287 void 288 acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi, 289 struct svc_req *req, cred_t *cr) 290 { 291 int error; 292 vnode_t *vp; 293 vattr_t va; 294 int checkwriteperm; 295 296 vp = nfs_fhtovp(&args->fh, exi); 297 if (vp == NULL) { 298 resp->status = NFSERR_STALE; 299 return; 300 } 301 302 /* 303 * If the file system is exported read only, it is not appropriate 304 * to check write permissions for regular files and directories. 305 * Special files are interpreted by the client, so the underlying 306 * permissions are sent back to the client for interpretation. 307 */ 308 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR)) 309 checkwriteperm = 0; 310 else 311 checkwriteperm = 1; 312 313 /* 314 * We need the mode so that we can correctly determine access 315 * permissions relative to a mandatory lock file. Access to 316 * mandatory lock files is denied on the server, so it might 317 * as well be reflected to the server during the open. 318 */ 319 va.va_mask = AT_MODE; 320 error = VOP_GETATTR(vp, &va, 0, cr); 321 if (error) { 322 VN_RELE(vp); 323 resp->status = puterrno(error); 324 return; 325 } 326 327 resp->resok.access = 0; 328 329 if (args->access & ACCESS2_READ) { 330 error = VOP_ACCESS(vp, VREAD, 0, cr); 331 if (!error && !MANDLOCK(vp, va.va_mode)) 332 resp->resok.access |= ACCESS2_READ; 333 } 334 if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) { 335 error = VOP_ACCESS(vp, VEXEC, 0, cr); 336 if (!error) 337 resp->resok.access |= ACCESS2_LOOKUP; 338 } 339 if (checkwriteperm && 340 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) { 341 error = VOP_ACCESS(vp, VWRITE, 0, cr); 342 if (!error && !MANDLOCK(vp, va.va_mode)) 343 resp->resok.access |= 344 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND)); 345 } 346 if (checkwriteperm && 347 (args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) { 348 error = VOP_ACCESS(vp, VWRITE, 0, cr); 349 if (!error) 350 resp->resok.access |= ACCESS2_DELETE; 351 } 352 if (args->access & ACCESS2_EXECUTE) { 353 error = VOP_ACCESS(vp, VEXEC, 0, cr); 354 if (!error && !MANDLOCK(vp, va.va_mode)) 355 resp->resok.access |= ACCESS2_EXECUTE; 356 } 357 358 va.va_mask = AT_ALL; 359 error = rfs4_delegated_getattr(vp, &va, 0, cr); 360 361 VN_RELE(vp); 362 363 /* check for overflowed values */ 364 if (!error) { 365 error = vattr_to_nattr(&va, &resp->resok.attr); 366 } 367 if (error) { 368 resp->status = puterrno(error); 369 return; 370 } 371 372 resp->status = NFS_OK; 373 } 374 375 void * 376 acl2_access_getfh(ACCESS2args *args) 377 { 378 379 return (&args->fh); 380 } 381 382 /* ARGSUSED */ 383 void 384 acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp, 385 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 386 { 387 int error; 388 int flags; 389 vnode_t *vp, *avp; 390 391 vp = nfs_fhtovp(&args->fh, exi); 392 if (vp == NULL) { 393 resp->status = NFSERR_STALE; 394 return; 395 } 396 397 flags = LOOKUP_XATTR; 398 if (args->create) 399 flags |= CREATE_XATTR_DIR; 400 else { 401 ulong_t val = 0; 402 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr); 403 if (!error && val == 0) { 404 VN_RELE(vp); 405 resp->status = NFSERR_NOENT; 406 return; 407 } 408 } 409 410 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr); 411 if (!error && avp == vp) { /* lookup of "" on old FS? */ 412 error = EINVAL; 413 VN_RELE(avp); 414 } 415 if (!error) { 416 struct vattr va; 417 va.va_mask = AT_ALL; 418 error = rfs4_delegated_getattr(avp, &va, 0, cr); 419 if (!error) { 420 error = vattr_to_nattr(&va, &resp->resok.attr); 421 if (!error) 422 error = makefh(&resp->resok.fh, avp, exi); 423 } 424 VN_RELE(avp); 425 } 426 427 VN_RELE(vp); 428 429 if (error) { 430 resp->status = puterrno(error); 431 return; 432 } 433 resp->status = NFS_OK; 434 } 435 436 void * 437 acl2_getxattrdir_getfh(GETXATTRDIR2args *args) 438 { 439 return (&args->fh); 440 } 441 442 /* ARGSUSED */ 443 void 444 acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi, 445 struct svc_req *req, cred_t *cr) 446 { 447 int error; 448 vnode_t *vp; 449 vattr_t *vap; 450 vattr_t va; 451 452 vap = NULL; 453 454 vp = nfs3_fhtovp(&args->fh, exi); 455 if (vp == NULL) { 456 error = ESTALE; 457 goto out; 458 } 459 460 #ifdef DEBUG 461 if (rfs3_do_post_op_attr) { 462 va.va_mask = AT_ALL; 463 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 464 } else 465 vap = NULL; 466 #else 467 va.va_mask = AT_ALL; 468 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 469 #endif 470 471 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 472 473 resp->resok.acl.vsa_mask = args->mask; 474 475 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr); 476 477 if (error == ENOSYS) { 478 /* 479 * If the underlying file system doesn't support 480 * aclent_t type acls, fabricate an acl. This is 481 * required in order to to support existing clients 482 * that require the call to VOP_GETSECATTR to 483 * succeed while making the assumption that all 484 * file systems support aclent_t type acls. This 485 * causes problems for servers exporting ZFS file 486 * systems because ZFS supports ace_t type acls, 487 * and fails (with ENOSYS) when asked for aclent_t 488 * type acls. 489 * 490 * Note: if the fs_fab_acl() fails, we have other problems. 491 * This error should be returned to the caller. 492 */ 493 error = fs_fab_acl(vp, &resp->resok.acl, 0, cr); 494 } 495 496 if (error) 497 goto out; 498 499 #ifdef DEBUG 500 if (rfs3_do_post_op_attr) { 501 va.va_mask = AT_ALL; 502 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 503 } else 504 vap = NULL; 505 #else 506 va.va_mask = AT_ALL; 507 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 508 #endif 509 510 VN_RELE(vp); 511 512 resp->status = NFS3_OK; 513 vattr_to_post_op_attr(vap, &resp->resok.attr); 514 if (!(args->mask & NA_ACL)) { 515 if (resp->resok.acl.vsa_aclcnt > 0 && 516 resp->resok.acl.vsa_aclentp != NULL) { 517 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 518 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 519 } 520 resp->resok.acl.vsa_aclentp = NULL; 521 } 522 if (!(args->mask & NA_DFACL)) { 523 if (resp->resok.acl.vsa_dfaclcnt > 0 && 524 resp->resok.acl.vsa_dfaclentp != NULL) { 525 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 526 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 527 } 528 resp->resok.acl.vsa_dfaclentp = NULL; 529 } 530 return; 531 532 out: 533 if (curthread->t_flag & T_WOULDBLOCK) { 534 curthread->t_flag &= ~T_WOULDBLOCK; 535 resp->status = NFS3ERR_JUKEBOX; 536 } else 537 resp->status = puterrno3(error); 538 out1: 539 if (vp != NULL) 540 VN_RELE(vp); 541 vattr_to_post_op_attr(vap, &resp->resfail.attr); 542 } 543 544 void * 545 acl3_getacl_getfh(GETACL3args *args) 546 { 547 548 return (&args->fh); 549 } 550 551 void 552 acl3_getacl_free(GETACL3res *resp) 553 { 554 555 if (resp->status == NFS3_OK) { 556 if (resp->resok.acl.vsa_aclcnt > 0 && 557 resp->resok.acl.vsa_aclentp != NULL) { 558 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 559 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 560 } 561 if (resp->resok.acl.vsa_dfaclcnt > 0 && 562 resp->resok.acl.vsa_dfaclentp != NULL) { 563 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 564 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 565 } 566 } 567 } 568 569 /* ARGSUSED */ 570 void 571 acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi, 572 struct svc_req *req, cred_t *cr) 573 { 574 int error; 575 vnode_t *vp; 576 vattr_t *vap; 577 vattr_t va; 578 579 vap = NULL; 580 581 vp = nfs3_fhtovp(&args->fh, exi); 582 if (vp == NULL) { 583 error = ESTALE; 584 goto out1; 585 } 586 587 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 588 589 #ifdef DEBUG 590 if (rfs3_do_post_op_attr) { 591 va.va_mask = AT_ALL; 592 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 593 } else 594 vap = NULL; 595 #else 596 va.va_mask = AT_ALL; 597 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 598 #endif 599 600 if (rdonly(exi, req) || vn_is_readonly(vp)) { 601 resp->status = NFS3ERR_ROFS; 602 goto out1; 603 } 604 605 error = VOP_SETSECATTR(vp, &args->acl, 0, cr); 606 607 #ifdef DEBUG 608 if (rfs3_do_post_op_attr) { 609 va.va_mask = AT_ALL; 610 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 611 } else 612 vap = NULL; 613 #else 614 va.va_mask = AT_ALL; 615 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 616 #endif 617 618 if (error) 619 goto out; 620 621 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 622 VN_RELE(vp); 623 624 resp->status = NFS3_OK; 625 vattr_to_post_op_attr(vap, &resp->resok.attr); 626 return; 627 628 out: 629 if (curthread->t_flag & T_WOULDBLOCK) { 630 curthread->t_flag &= ~T_WOULDBLOCK; 631 resp->status = NFS3ERR_JUKEBOX; 632 } else 633 resp->status = puterrno3(error); 634 out1: 635 if (vp != NULL) { 636 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 637 VN_RELE(vp); 638 } 639 vattr_to_post_op_attr(vap, &resp->resfail.attr); 640 } 641 642 void * 643 acl3_setacl_getfh(SETACL3args *args) 644 { 645 646 return (&args->fh); 647 } 648 649 /* ARGSUSED */ 650 void 651 acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp, 652 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 653 { 654 int error; 655 int flags; 656 vnode_t *vp, *avp; 657 658 vp = nfs3_fhtovp(&args->fh, exi); 659 if (vp == NULL) { 660 resp->status = NFS3ERR_STALE; 661 return; 662 } 663 664 flags = LOOKUP_XATTR; 665 if (args->create) 666 flags |= CREATE_XATTR_DIR; 667 else { 668 ulong_t val = 0; 669 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr); 670 if (!error && val == 0) { 671 VN_RELE(vp); 672 resp->status = NFS3ERR_NOENT; 673 return; 674 } 675 } 676 677 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr); 678 if (!error && avp == vp) { /* lookup of "" on old FS? */ 679 error = EINVAL; 680 VN_RELE(avp); 681 } 682 if (!error) { 683 struct vattr va; 684 va.va_mask = AT_ALL; 685 error = rfs4_delegated_getattr(avp, &va, 0, cr); 686 if (!error) { 687 vattr_to_post_op_attr(&va, &resp->resok.attr); 688 error = makefh3(&resp->resok.fh, avp, exi); 689 } 690 VN_RELE(avp); 691 } 692 693 VN_RELE(vp); 694 695 if (error) { 696 resp->status = puterrno3(error); 697 return; 698 } 699 resp->status = NFS3_OK; 700 } 701 702 void * 703 acl3_getxattrdir_getfh(GETXATTRDIR3args *args) 704 { 705 return (&args->fh); 706 } 707