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 va.va_mask = AT_ALL; 463 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 464 465 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 466 467 resp->resok.acl.vsa_mask = args->mask; 468 469 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL); 470 471 if ((error == ENOSYS) && !(exi->exi_export.ex_flags & EX_NOACLFAB)) { 472 /* 473 * If the underlying file system doesn't support 474 * aclent_t type acls, fabricate an acl. This is 475 * required in order to to support existing clients 476 * that require the call to VOP_GETSECATTR to 477 * succeed while making the assumption that all 478 * file systems support aclent_t type acls. This 479 * causes problems for servers exporting ZFS file 480 * systems because ZFS supports ace_t type acls, 481 * and fails (with ENOSYS) when asked for aclent_t 482 * type acls. 483 * 484 * Note: if the fs_fab_acl() fails, we have other problems. 485 * This error should be returned to the caller. 486 */ 487 error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL); 488 } 489 490 if (error) 491 goto out; 492 493 va.va_mask = AT_ALL; 494 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 495 496 VN_RELE(vp); 497 498 resp->status = NFS3_OK; 499 vattr_to_post_op_attr(vap, &resp->resok.attr); 500 if (!(args->mask & NA_ACL)) { 501 if (resp->resok.acl.vsa_aclcnt > 0 && 502 resp->resok.acl.vsa_aclentp != NULL) { 503 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 504 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 505 } 506 resp->resok.acl.vsa_aclentp = NULL; 507 } 508 if (!(args->mask & NA_DFACL)) { 509 if (resp->resok.acl.vsa_dfaclcnt > 0 && 510 resp->resok.acl.vsa_dfaclentp != NULL) { 511 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 512 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 513 } 514 resp->resok.acl.vsa_dfaclentp = NULL; 515 } 516 return; 517 518 out: 519 if (curthread->t_flag & T_WOULDBLOCK) { 520 curthread->t_flag &= ~T_WOULDBLOCK; 521 resp->status = NFS3ERR_JUKEBOX; 522 } else 523 resp->status = puterrno3(error); 524 out1: 525 if (vp != NULL) 526 VN_RELE(vp); 527 vattr_to_post_op_attr(vap, &resp->resfail.attr); 528 } 529 530 void * 531 acl3_getacl_getfh(GETACL3args *args) 532 { 533 534 return (&args->fh); 535 } 536 537 void 538 acl3_getacl_free(GETACL3res *resp) 539 { 540 541 if (resp->status == NFS3_OK) { 542 if (resp->resok.acl.vsa_aclcnt > 0 && 543 resp->resok.acl.vsa_aclentp != NULL) { 544 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 545 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 546 } 547 if (resp->resok.acl.vsa_dfaclcnt > 0 && 548 resp->resok.acl.vsa_dfaclentp != NULL) { 549 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 550 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 551 } 552 } 553 } 554 555 /* ARGSUSED */ 556 void 557 acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi, 558 struct svc_req *req, cred_t *cr) 559 { 560 int error; 561 vnode_t *vp; 562 vattr_t *vap; 563 vattr_t va; 564 565 vap = NULL; 566 567 vp = nfs3_fhtovp(&args->fh, exi); 568 if (vp == NULL) { 569 error = ESTALE; 570 goto out1; 571 } 572 573 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 574 575 va.va_mask = AT_ALL; 576 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 577 578 if (rdonly(exi, req) || vn_is_readonly(vp)) { 579 resp->status = NFS3ERR_ROFS; 580 goto out1; 581 } 582 583 error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL); 584 585 va.va_mask = AT_ALL; 586 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 587 588 if (error) 589 goto out; 590 591 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 592 VN_RELE(vp); 593 594 resp->status = NFS3_OK; 595 vattr_to_post_op_attr(vap, &resp->resok.attr); 596 return; 597 598 out: 599 if (curthread->t_flag & T_WOULDBLOCK) { 600 curthread->t_flag &= ~T_WOULDBLOCK; 601 resp->status = NFS3ERR_JUKEBOX; 602 } else 603 resp->status = puterrno3(error); 604 out1: 605 if (vp != NULL) { 606 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 607 VN_RELE(vp); 608 } 609 vattr_to_post_op_attr(vap, &resp->resfail.attr); 610 } 611 612 void * 613 acl3_setacl_getfh(SETACL3args *args) 614 { 615 616 return (&args->fh); 617 } 618 619 /* ARGSUSED */ 620 void 621 acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp, 622 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 623 { 624 int error; 625 int flags; 626 vnode_t *vp, *avp; 627 628 vp = nfs3_fhtovp(&args->fh, exi); 629 if (vp == NULL) { 630 resp->status = NFS3ERR_STALE; 631 return; 632 } 633 634 flags = LOOKUP_XATTR; 635 if (args->create) 636 flags |= CREATE_XATTR_DIR; 637 else { 638 ulong_t val = 0; 639 640 error = VOP_PATHCONF(vp, _PC_SATTR_EXISTS, &val, cr, NULL); 641 if (!error && val == 0) { 642 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, 643 &val, cr, NULL); 644 if (!error && val == 0) { 645 VN_RELE(vp); 646 resp->status = NFS3ERR_NOENT; 647 return; 648 } 649 } 650 } 651 652 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr, 653 NULL, NULL, NULL); 654 if (!error && avp == vp) { /* lookup of "" on old FS? */ 655 error = EINVAL; 656 VN_RELE(avp); 657 } 658 if (!error) { 659 struct vattr va; 660 va.va_mask = AT_ALL; 661 error = rfs4_delegated_getattr(avp, &va, 0, cr); 662 if (!error) { 663 vattr_to_post_op_attr(&va, &resp->resok.attr); 664 error = makefh3(&resp->resok.fh, avp, exi); 665 } 666 VN_RELE(avp); 667 } 668 669 VN_RELE(vp); 670 671 if (error) { 672 resp->status = puterrno3(error); 673 return; 674 } 675 resp->status = NFS3_OK; 676 } 677 678 void * 679 acl3_getxattrdir_getfh(GETXATTRDIR3args *args) 680 { 681 return (&args->fh); 682 }