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 2007 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, NULL); 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, NULL); 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, NULL); 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, NULL); 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, NULL); 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, NULL); 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, NULL); 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, NULL); 349 if (!error) 350 resp->resok.access |= ACCESS2_DELETE; 351 } 352 if (args->access & ACCESS2_EXECUTE) { 353 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 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, NULL); 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 NULL, NULL, NULL); 412 if (!error && avp == vp) { /* lookup of "" on old FS? */ 413 error = EINVAL; 414 VN_RELE(avp); 415 } 416 if (!error) { 417 struct vattr va; 418 va.va_mask = AT_ALL; 419 error = rfs4_delegated_getattr(avp, &va, 0, cr); 420 if (!error) { 421 error = vattr_to_nattr(&va, &resp->resok.attr); 422 if (!error) 423 error = makefh(&resp->resok.fh, avp, exi); 424 } 425 VN_RELE(avp); 426 } 427 428 VN_RELE(vp); 429 430 if (error) { 431 resp->status = puterrno(error); 432 return; 433 } 434 resp->status = NFS_OK; 435 } 436 437 void * 438 acl2_getxattrdir_getfh(GETXATTRDIR2args *args) 439 { 440 return (&args->fh); 441 } 442 443 /* ARGSUSED */ 444 void 445 acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi, 446 struct svc_req *req, cred_t *cr) 447 { 448 int error; 449 vnode_t *vp; 450 vattr_t *vap; 451 vattr_t va; 452 453 vap = NULL; 454 455 vp = nfs3_fhtovp(&args->fh, exi); 456 if (vp == NULL) { 457 error = ESTALE; 458 goto out; 459 } 460 461 #ifdef DEBUG 462 if (rfs3_do_post_op_attr) { 463 va.va_mask = AT_ALL; 464 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 465 } else 466 vap = NULL; 467 #else 468 va.va_mask = AT_ALL; 469 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 470 #endif 471 472 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 473 474 resp->resok.acl.vsa_mask = args->mask; 475 476 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL); 477 478 if (error == ENOSYS) { 479 /* 480 * If the underlying file system doesn't support 481 * aclent_t type acls, fabricate an acl. This is 482 * required in order to to support existing clients 483 * that require the call to VOP_GETSECATTR to 484 * succeed while making the assumption that all 485 * file systems support aclent_t type acls. This 486 * causes problems for servers exporting ZFS file 487 * systems because ZFS supports ace_t type acls, 488 * and fails (with ENOSYS) when asked for aclent_t 489 * type acls. 490 * 491 * Note: if the fs_fab_acl() fails, we have other problems. 492 * This error should be returned to the caller. 493 */ 494 error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL); 495 } 496 497 if (error) 498 goto out; 499 500 #ifdef DEBUG 501 if (rfs3_do_post_op_attr) { 502 va.va_mask = AT_ALL; 503 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 504 } else 505 vap = NULL; 506 #else 507 va.va_mask = AT_ALL; 508 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 509 #endif 510 511 VN_RELE(vp); 512 513 resp->status = NFS3_OK; 514 vattr_to_post_op_attr(vap, &resp->resok.attr); 515 if (!(args->mask & NA_ACL)) { 516 if (resp->resok.acl.vsa_aclcnt > 0 && 517 resp->resok.acl.vsa_aclentp != NULL) { 518 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 519 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 520 } 521 resp->resok.acl.vsa_aclentp = NULL; 522 } 523 if (!(args->mask & NA_DFACL)) { 524 if (resp->resok.acl.vsa_dfaclcnt > 0 && 525 resp->resok.acl.vsa_dfaclentp != NULL) { 526 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 527 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 528 } 529 resp->resok.acl.vsa_dfaclentp = NULL; 530 } 531 return; 532 533 out: 534 if (curthread->t_flag & T_WOULDBLOCK) { 535 curthread->t_flag &= ~T_WOULDBLOCK; 536 resp->status = NFS3ERR_JUKEBOX; 537 } else 538 resp->status = puterrno3(error); 539 out1: 540 if (vp != NULL) 541 VN_RELE(vp); 542 vattr_to_post_op_attr(vap, &resp->resfail.attr); 543 } 544 545 void * 546 acl3_getacl_getfh(GETACL3args *args) 547 { 548 549 return (&args->fh); 550 } 551 552 void 553 acl3_getacl_free(GETACL3res *resp) 554 { 555 556 if (resp->status == NFS3_OK) { 557 if (resp->resok.acl.vsa_aclcnt > 0 && 558 resp->resok.acl.vsa_aclentp != NULL) { 559 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 560 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 561 } 562 if (resp->resok.acl.vsa_dfaclcnt > 0 && 563 resp->resok.acl.vsa_dfaclentp != NULL) { 564 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 565 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 566 } 567 } 568 } 569 570 /* ARGSUSED */ 571 void 572 acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi, 573 struct svc_req *req, cred_t *cr) 574 { 575 int error; 576 vnode_t *vp; 577 vattr_t *vap; 578 vattr_t va; 579 580 vap = NULL; 581 582 vp = nfs3_fhtovp(&args->fh, exi); 583 if (vp == NULL) { 584 error = ESTALE; 585 goto out1; 586 } 587 588 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 589 590 #ifdef DEBUG 591 if (rfs3_do_post_op_attr) { 592 va.va_mask = AT_ALL; 593 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 594 } else 595 vap = NULL; 596 #else 597 va.va_mask = AT_ALL; 598 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 599 #endif 600 601 if (rdonly(exi, req) || vn_is_readonly(vp)) { 602 resp->status = NFS3ERR_ROFS; 603 goto out1; 604 } 605 606 error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL); 607 608 #ifdef DEBUG 609 if (rfs3_do_post_op_attr) { 610 va.va_mask = AT_ALL; 611 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 612 } else 613 vap = NULL; 614 #else 615 va.va_mask = AT_ALL; 616 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 617 #endif 618 619 if (error) 620 goto out; 621 622 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 623 VN_RELE(vp); 624 625 resp->status = NFS3_OK; 626 vattr_to_post_op_attr(vap, &resp->resok.attr); 627 return; 628 629 out: 630 if (curthread->t_flag & T_WOULDBLOCK) { 631 curthread->t_flag &= ~T_WOULDBLOCK; 632 resp->status = NFS3ERR_JUKEBOX; 633 } else 634 resp->status = puterrno3(error); 635 out1: 636 if (vp != NULL) { 637 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 638 VN_RELE(vp); 639 } 640 vattr_to_post_op_attr(vap, &resp->resfail.attr); 641 } 642 643 void * 644 acl3_setacl_getfh(SETACL3args *args) 645 { 646 647 return (&args->fh); 648 } 649 650 /* ARGSUSED */ 651 void 652 acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp, 653 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 654 { 655 int error; 656 int flags; 657 vnode_t *vp, *avp; 658 659 vp = nfs3_fhtovp(&args->fh, exi); 660 if (vp == NULL) { 661 resp->status = NFS3ERR_STALE; 662 return; 663 } 664 665 flags = LOOKUP_XATTR; 666 if (args->create) 667 flags |= CREATE_XATTR_DIR; 668 else { 669 ulong_t val = 0; 670 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr, NULL); 671 if (!error && val == 0) { 672 VN_RELE(vp); 673 resp->status = NFS3ERR_NOENT; 674 return; 675 } 676 } 677 678 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr, 679 NULL, NULL, NULL); 680 if (!error && avp == vp) { /* lookup of "" on old FS? */ 681 error = EINVAL; 682 VN_RELE(avp); 683 } 684 if (!error) { 685 struct vattr va; 686 va.va_mask = AT_ALL; 687 error = rfs4_delegated_getattr(avp, &va, 0, cr); 688 if (!error) { 689 vattr_to_post_op_attr(&va, &resp->resok.attr); 690 error = makefh3(&resp->resok.fh, avp, exi); 691 } 692 VN_RELE(avp); 693 } 694 695 VN_RELE(vp); 696 697 if (error) { 698 resp->status = puterrno3(error); 699 return; 700 } 701 resp->status = NFS3_OK; 702 } 703 704 void * 705 acl3_getxattrdir_getfh(GETXATTRDIR3args *args) 706 { 707 return (&args->fh); 708 } 709