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