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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. 24 * All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/systm.h> 33 #include <sys/cred.h> 34 #include <sys/proc.h> 35 #include <sys/user.h> 36 #include <sys/buf.h> 37 #include <sys/vfs.h> 38 #include <sys/vnode.h> 39 #include <sys/pathname.h> 40 #include <sys/uio.h> 41 #include <sys/file.h> 42 #include <sys/stat.h> 43 #include <sys/errno.h> 44 #include <sys/socket.h> 45 #include <sys/sysmacros.h> 46 #include <sys/siginfo.h> 47 #include <sys/tiuser.h> 48 #include <sys/statvfs.h> 49 #include <sys/t_kuser.h> 50 #include <sys/kmem.h> 51 #include <sys/kstat.h> 52 #include <sys/acl.h> 53 #include <sys/dirent.h> 54 #include <sys/cmn_err.h> 55 #include <sys/debug.h> 56 #include <sys/unistd.h> 57 #include <sys/vtrace.h> 58 #include <sys/mode.h> 59 60 #include <rpc/types.h> 61 #include <rpc/auth.h> 62 #include <rpc/svc.h> 63 #include <rpc/xdr.h> 64 65 #include <nfs/nfs.h> 66 #include <nfs/export.h> 67 #include <nfs/nfssys.h> 68 #include <nfs/nfs_clnt.h> 69 #include <nfs/nfs_acl.h> 70 71 #include <fs/fs_subr.h> 72 73 /* 74 * These are the interface routines for the server side of the 75 * NFS ACL server. See the NFS ACL protocol specification 76 * for a description of this interface. 77 */ 78 79 /* ARGSUSED */ 80 void 81 acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi, 82 struct svc_req *req, cred_t *cr) 83 { 84 int error; 85 vnode_t *vp; 86 vattr_t va; 87 88 vp = nfs_fhtovp(&args->fh, exi); 89 if (vp == NULL) { 90 resp->status = NFSERR_STALE; 91 return; 92 } 93 94 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 95 96 resp->resok.acl.vsa_mask = args->mask; 97 98 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr); 99 100 if (error == ENOSYS) { 101 /* 102 * If the underlying file system doesn't support 103 * aclent_t type acls, fabricate an acl. This is 104 * required in order to to support existing clients 105 * that require the call to VOP_GETSECATTR to 106 * succeed while making the assumption that all 107 * file systems support aclent_t type acls. This 108 * causes problems for servers exporting ZFS file 109 * systems because ZFS supports ace_t type acls, 110 * and fails (with ENOSYS) when asked for aclent_t 111 * type acls. 112 * 113 * Note: if the fs_fab_acl() fails, we have other problems. 114 * This error should be returned to the caller. 115 */ 116 error = fs_fab_acl(vp, &resp->resok.acl, 0, cr); 117 } 118 119 if (error) { 120 VN_RELE(vp); 121 resp->status = puterrno(error); 122 return; 123 } 124 125 va.va_mask = AT_ALL; 126 error = rfs4_delegated_getattr(vp, &va, 0, cr); 127 128 VN_RELE(vp); 129 130 /* check for overflowed values */ 131 if (!error) { 132 error = vattr_to_nattr(&va, &resp->resok.attr); 133 } 134 if (error) { 135 resp->status = puterrno(error); 136 if (resp->resok.acl.vsa_aclcnt > 0 && 137 resp->resok.acl.vsa_aclentp != NULL) { 138 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 139 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 140 } 141 if (resp->resok.acl.vsa_dfaclcnt > 0 && 142 resp->resok.acl.vsa_dfaclentp != NULL) { 143 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 144 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 145 } 146 return; 147 } 148 149 resp->status = NFS_OK; 150 if (!(args->mask & NA_ACL)) { 151 if (resp->resok.acl.vsa_aclcnt > 0 && 152 resp->resok.acl.vsa_aclentp != NULL) { 153 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 154 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 155 } 156 resp->resok.acl.vsa_aclentp = NULL; 157 } 158 if (!(args->mask & NA_DFACL)) { 159 if (resp->resok.acl.vsa_dfaclcnt > 0 && 160 resp->resok.acl.vsa_dfaclentp != NULL) { 161 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 162 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 163 } 164 resp->resok.acl.vsa_dfaclentp = NULL; 165 } 166 } 167 168 fhandle_t * 169 acl2_getacl_getfh(GETACL2args *args) 170 { 171 172 return (&args->fh); 173 } 174 175 void 176 acl2_getacl_free(GETACL2res *resp) 177 { 178 179 if (resp->status == NFS_OK) { 180 if (resp->resok.acl.vsa_aclcnt > 0 && 181 resp->resok.acl.vsa_aclentp != NULL) { 182 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 183 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 184 } 185 if (resp->resok.acl.vsa_dfaclcnt > 0 && 186 resp->resok.acl.vsa_dfaclentp != NULL) { 187 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 188 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 189 } 190 } 191 } 192 193 /* ARGSUSED */ 194 void 195 acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi, 196 struct svc_req *req, cred_t *cr) 197 { 198 int error; 199 vnode_t *vp; 200 vattr_t va; 201 202 vp = nfs_fhtovp(&args->fh, exi); 203 if (vp == NULL) { 204 resp->status = NFSERR_STALE; 205 return; 206 } 207 208 if (rdonly(exi, req) || vn_is_readonly(vp)) { 209 VN_RELE(vp); 210 resp->status = NFSERR_ROFS; 211 return; 212 } 213 214 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 215 error = VOP_SETSECATTR(vp, &args->acl, 0, cr); 216 if (error) { 217 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 218 VN_RELE(vp); 219 resp->status = puterrno(error); 220 return; 221 } 222 223 va.va_mask = AT_ALL; 224 error = rfs4_delegated_getattr(vp, &va, 0, cr); 225 226 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 227 VN_RELE(vp); 228 229 /* check for overflowed values */ 230 if (!error) { 231 error = vattr_to_nattr(&va, &resp->resok.attr); 232 } 233 if (error) { 234 resp->status = puterrno(error); 235 return; 236 } 237 238 resp->status = NFS_OK; 239 } 240 241 fhandle_t * 242 acl2_setacl_getfh(SETACL2args *args) 243 { 244 245 return (&args->fh); 246 } 247 248 /* ARGSUSED */ 249 void 250 acl2_getattr(GETATTR2args *args, GETATTR2res *resp, struct exportinfo *exi, 251 struct svc_req *req, cred_t *cr) 252 { 253 int error; 254 vnode_t *vp; 255 vattr_t va; 256 257 vp = nfs_fhtovp(&args->fh, exi); 258 if (vp == NULL) { 259 resp->status = NFSERR_STALE; 260 return; 261 } 262 263 va.va_mask = AT_ALL; 264 error = rfs4_delegated_getattr(vp, &va, 0, cr); 265 266 VN_RELE(vp); 267 268 /* check for overflowed values */ 269 if (!error) { 270 error = vattr_to_nattr(&va, &resp->resok.attr); 271 } 272 if (error) { 273 resp->status = puterrno(error); 274 return; 275 } 276 277 resp->status = NFS_OK; 278 } 279 280 fhandle_t * 281 acl2_getattr_getfh(GETATTR2args *args) 282 { 283 284 return (&args->fh); 285 } 286 287 /* ARGSUSED */ 288 void 289 acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi, 290 struct svc_req *req, cred_t *cr) 291 { 292 int error; 293 vnode_t *vp; 294 vattr_t va; 295 int checkwriteperm; 296 297 vp = nfs_fhtovp(&args->fh, exi); 298 if (vp == NULL) { 299 resp->status = NFSERR_STALE; 300 return; 301 } 302 303 /* 304 * If the file system is exported read only, it is not appropriate 305 * to check write permissions for regular files and directories. 306 * Special files are interpreted by the client, so the underlying 307 * permissions are sent back to the client for interpretation. 308 */ 309 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR)) 310 checkwriteperm = 0; 311 else 312 checkwriteperm = 1; 313 314 /* 315 * We need the mode so that we can correctly determine access 316 * permissions relative to a mandatory lock file. Access to 317 * mandatory lock files is denied on the server, so it might 318 * as well be reflected to the server during the open. 319 */ 320 va.va_mask = AT_MODE; 321 error = VOP_GETATTR(vp, &va, 0, cr); 322 if (error) { 323 VN_RELE(vp); 324 resp->status = puterrno(error); 325 return; 326 } 327 328 resp->resok.access = 0; 329 330 if (args->access & ACCESS2_READ) { 331 error = VOP_ACCESS(vp, VREAD, 0, cr); 332 if (!error && !MANDLOCK(vp, va.va_mode)) 333 resp->resok.access |= ACCESS2_READ; 334 } 335 if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) { 336 error = VOP_ACCESS(vp, VEXEC, 0, cr); 337 if (!error) 338 resp->resok.access |= ACCESS2_LOOKUP; 339 } 340 if (checkwriteperm && 341 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) { 342 error = VOP_ACCESS(vp, VWRITE, 0, cr); 343 if (!error && !MANDLOCK(vp, va.va_mode)) 344 resp->resok.access |= 345 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND)); 346 } 347 if (checkwriteperm && 348 (args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) { 349 error = VOP_ACCESS(vp, VWRITE, 0, cr); 350 if (!error) 351 resp->resok.access |= ACCESS2_DELETE; 352 } 353 if (args->access & ACCESS2_EXECUTE) { 354 error = VOP_ACCESS(vp, VEXEC, 0, cr); 355 if (!error && !MANDLOCK(vp, va.va_mode)) 356 resp->resok.access |= ACCESS2_EXECUTE; 357 } 358 359 va.va_mask = AT_ALL; 360 error = rfs4_delegated_getattr(vp, &va, 0, cr); 361 362 VN_RELE(vp); 363 364 /* check for overflowed values */ 365 if (!error) { 366 error = vattr_to_nattr(&va, &resp->resok.attr); 367 } 368 if (error) { 369 resp->status = puterrno(error); 370 return; 371 } 372 373 resp->status = NFS_OK; 374 } 375 376 fhandle_t * 377 acl2_access_getfh(ACCESS2args *args) 378 { 379 380 return (&args->fh); 381 } 382 383 /* ARGSUSED */ 384 void 385 acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp, 386 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 387 { 388 int error; 389 int flags; 390 vnode_t *vp, *avp; 391 392 vp = nfs_fhtovp(&args->fh, exi); 393 if (vp == NULL) { 394 resp->status = NFSERR_STALE; 395 return; 396 } 397 398 flags = LOOKUP_XATTR; 399 if (args->create) 400 flags |= CREATE_XATTR_DIR; 401 else { 402 ulong_t val = 0; 403 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr); 404 if (!error && val == 0) { 405 VN_RELE(vp); 406 resp->status = NFSERR_NOENT; 407 return; 408 } 409 } 410 411 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr); 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 fhandle_t * 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); 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); 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 fhandle_t * 546 acl3_getacl_getfh(GETACL3args *args) 547 { 548 549 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 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); 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 fhandle_t * 644 acl3_setacl_getfh(SETACL3args *args) 645 { 646 647 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 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); 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 if (!error && avp == vp) { /* lookup of "" on old FS? */ 680 error = EINVAL; 681 VN_RELE(avp); 682 } 683 if (!error) { 684 struct vattr va; 685 va.va_mask = AT_ALL; 686 error = rfs4_delegated_getattr(avp, &va, 0, cr); 687 if (!error) { 688 vattr_to_post_op_attr(&va, &resp->resok.attr); 689 error = makefh3(&resp->resok.fh, avp, exi); 690 } 691 VN_RELE(avp); 692 } 693 694 VN_RELE(vp); 695 696 if (error) { 697 resp->status = puterrno3(error); 698 return; 699 } 700 resp->status = NFS3_OK; 701 } 702 703 fhandle_t * 704 acl3_getxattrdir_getfh(GETXATTRDIR3args *args) 705 { 706 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 707 } 708