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