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 2004 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 /* 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); 97 98 if (error) { 99 VN_RELE(vp); 100 resp->status = puterrno(error); 101 return; 102 } 103 104 va.va_mask = AT_ALL; 105 error = rfs4_delegated_getattr(vp, &va, 0, cr); 106 107 VN_RELE(vp); 108 109 /* check for overflowed values */ 110 if (!error) { 111 error = vattr_to_nattr(&va, &resp->resok.attr); 112 } 113 if (error) { 114 resp->status = puterrno(error); 115 if (resp->resok.acl.vsa_aclcnt > 0 && 116 resp->resok.acl.vsa_aclentp != NULL) { 117 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 118 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 119 } 120 if (resp->resok.acl.vsa_dfaclcnt > 0 && 121 resp->resok.acl.vsa_dfaclentp != NULL) { 122 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 123 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 124 } 125 return; 126 } 127 128 resp->status = NFS_OK; 129 if (!(args->mask & NA_ACL)) { 130 if (resp->resok.acl.vsa_aclcnt > 0 && 131 resp->resok.acl.vsa_aclentp != NULL) { 132 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 133 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 134 } 135 resp->resok.acl.vsa_aclentp = NULL; 136 } 137 if (!(args->mask & NA_DFACL)) { 138 if (resp->resok.acl.vsa_dfaclcnt > 0 && 139 resp->resok.acl.vsa_dfaclentp != NULL) { 140 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 141 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 142 } 143 resp->resok.acl.vsa_dfaclentp = NULL; 144 } 145 } 146 147 fhandle_t * 148 acl2_getacl_getfh(GETACL2args *args) 149 { 150 151 return (&args->fh); 152 } 153 154 void 155 acl2_getacl_free(GETACL2res *resp) 156 { 157 158 if (resp->status == NFS_OK) { 159 if (resp->resok.acl.vsa_aclcnt > 0 && 160 resp->resok.acl.vsa_aclentp != NULL) { 161 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 162 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 163 } 164 if (resp->resok.acl.vsa_dfaclcnt > 0 && 165 resp->resok.acl.vsa_dfaclentp != NULL) { 166 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 167 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 168 } 169 } 170 } 171 172 /* ARGSUSED */ 173 void 174 acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi, 175 struct svc_req *req, cred_t *cr) 176 { 177 int error; 178 vnode_t *vp; 179 vattr_t va; 180 181 vp = nfs_fhtovp(&args->fh, exi); 182 if (vp == NULL) { 183 resp->status = NFSERR_STALE; 184 return; 185 } 186 187 if (rdonly(exi, req) || vn_is_readonly(vp)) { 188 VN_RELE(vp); 189 resp->status = NFSERR_ROFS; 190 return; 191 } 192 193 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 194 error = VOP_SETSECATTR(vp, &args->acl, 0, cr); 195 if (error) { 196 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 197 VN_RELE(vp); 198 resp->status = puterrno(error); 199 return; 200 } 201 202 va.va_mask = AT_ALL; 203 error = rfs4_delegated_getattr(vp, &va, 0, cr); 204 205 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 206 VN_RELE(vp); 207 208 /* check for overflowed values */ 209 if (!error) { 210 error = vattr_to_nattr(&va, &resp->resok.attr); 211 } 212 if (error) { 213 resp->status = puterrno(error); 214 return; 215 } 216 217 resp->status = NFS_OK; 218 } 219 220 fhandle_t * 221 acl2_setacl_getfh(SETACL2args *args) 222 { 223 224 return (&args->fh); 225 } 226 227 /* ARGSUSED */ 228 void 229 acl2_getattr(GETATTR2args *args, GETATTR2res *resp, struct exportinfo *exi, 230 struct svc_req *req, cred_t *cr) 231 { 232 int error; 233 vnode_t *vp; 234 vattr_t va; 235 236 vp = nfs_fhtovp(&args->fh, exi); 237 if (vp == NULL) { 238 resp->status = NFSERR_STALE; 239 return; 240 } 241 242 va.va_mask = AT_ALL; 243 error = rfs4_delegated_getattr(vp, &va, 0, cr); 244 245 VN_RELE(vp); 246 247 /* check for overflowed values */ 248 if (!error) { 249 error = vattr_to_nattr(&va, &resp->resok.attr); 250 } 251 if (error) { 252 resp->status = puterrno(error); 253 return; 254 } 255 256 resp->status = NFS_OK; 257 } 258 259 fhandle_t * 260 acl2_getattr_getfh(GETATTR2args *args) 261 { 262 263 return (&args->fh); 264 } 265 266 /* ARGSUSED */ 267 void 268 acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi, 269 struct svc_req *req, cred_t *cr) 270 { 271 int error; 272 vnode_t *vp; 273 vattr_t va; 274 int checkwriteperm; 275 276 vp = nfs_fhtovp(&args->fh, exi); 277 if (vp == NULL) { 278 resp->status = NFSERR_STALE; 279 return; 280 } 281 282 /* 283 * If the file system is exported read only, it is not appropriate 284 * to check write permissions for regular files and directories. 285 * Special files are interpreted by the client, so the underlying 286 * permissions are sent back to the client for interpretation. 287 */ 288 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR)) 289 checkwriteperm = 0; 290 else 291 checkwriteperm = 1; 292 293 /* 294 * We need the mode so that we can correctly determine access 295 * permissions relative to a mandatory lock file. Access to 296 * mandatory lock files is denied on the server, so it might 297 * as well be reflected to the server during the open. 298 */ 299 va.va_mask = AT_MODE; 300 error = VOP_GETATTR(vp, &va, 0, cr); 301 if (error) { 302 VN_RELE(vp); 303 resp->status = puterrno(error); 304 return; 305 } 306 307 resp->resok.access = 0; 308 309 if (args->access & ACCESS2_READ) { 310 error = VOP_ACCESS(vp, VREAD, 0, cr); 311 if (!error && !MANDLOCK(vp, va.va_mode)) 312 resp->resok.access |= ACCESS2_READ; 313 } 314 if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) { 315 error = VOP_ACCESS(vp, VEXEC, 0, cr); 316 if (!error) 317 resp->resok.access |= ACCESS2_LOOKUP; 318 } 319 if (checkwriteperm && 320 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) { 321 error = VOP_ACCESS(vp, VWRITE, 0, cr); 322 if (!error && !MANDLOCK(vp, va.va_mode)) 323 resp->resok.access |= 324 (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND)); 325 } 326 if (checkwriteperm && 327 (args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) { 328 error = VOP_ACCESS(vp, VWRITE, 0, cr); 329 if (!error) 330 resp->resok.access |= ACCESS2_DELETE; 331 } 332 if (args->access & ACCESS2_EXECUTE) { 333 error = VOP_ACCESS(vp, VEXEC, 0, cr); 334 if (!error && !MANDLOCK(vp, va.va_mode)) 335 resp->resok.access |= ACCESS2_EXECUTE; 336 } 337 338 va.va_mask = AT_ALL; 339 error = rfs4_delegated_getattr(vp, &va, 0, cr); 340 341 VN_RELE(vp); 342 343 /* check for overflowed values */ 344 if (!error) { 345 error = vattr_to_nattr(&va, &resp->resok.attr); 346 } 347 if (error) { 348 resp->status = puterrno(error); 349 return; 350 } 351 352 resp->status = NFS_OK; 353 } 354 355 fhandle_t * 356 acl2_access_getfh(ACCESS2args *args) 357 { 358 359 return (&args->fh); 360 } 361 362 /* ARGSUSED */ 363 void 364 acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp, 365 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 366 { 367 int error; 368 int flags; 369 vnode_t *vp, *avp; 370 371 vp = nfs_fhtovp(&args->fh, exi); 372 if (vp == NULL) { 373 resp->status = NFSERR_STALE; 374 return; 375 } 376 377 flags = LOOKUP_XATTR; 378 if (args->create) 379 flags |= CREATE_XATTR_DIR; 380 else { 381 ulong_t val = 0; 382 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr); 383 if (!error && val == 0) { 384 VN_RELE(vp); 385 resp->status = NFSERR_NOENT; 386 return; 387 } 388 } 389 390 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr); 391 if (!error && avp == vp) { /* lookup of "" on old FS? */ 392 error = EINVAL; 393 VN_RELE(avp); 394 } 395 if (!error) { 396 struct vattr va; 397 va.va_mask = AT_ALL; 398 error = rfs4_delegated_getattr(avp, &va, 0, cr); 399 if (!error) { 400 error = vattr_to_nattr(&va, &resp->resok.attr); 401 if (!error) 402 error = makefh(&resp->resok.fh, avp, exi); 403 } 404 VN_RELE(avp); 405 } 406 407 VN_RELE(vp); 408 409 if (error) { 410 resp->status = puterrno(error); 411 return; 412 } 413 resp->status = NFS_OK; 414 } 415 416 fhandle_t * 417 acl2_getxattrdir_getfh(GETXATTRDIR2args *args) 418 { 419 return (&args->fh); 420 } 421 422 /* ARGSUSED */ 423 void 424 acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi, 425 struct svc_req *req, cred_t *cr) 426 { 427 int error; 428 vnode_t *vp; 429 vattr_t *vap; 430 vattr_t va; 431 432 vap = NULL; 433 434 vp = nfs3_fhtovp(&args->fh, exi); 435 if (vp == NULL) { 436 error = ESTALE; 437 goto out; 438 } 439 440 #ifdef DEBUG 441 if (rfs3_do_post_op_attr) { 442 va.va_mask = AT_ALL; 443 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 444 } else 445 vap = NULL; 446 #else 447 va.va_mask = AT_ALL; 448 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 449 #endif 450 451 bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl)); 452 453 resp->resok.acl.vsa_mask = args->mask; 454 455 error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr); 456 457 if (error) 458 goto out; 459 460 #ifdef DEBUG 461 if (rfs3_do_post_op_attr) { 462 va.va_mask = AT_ALL; 463 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 464 } else 465 vap = NULL; 466 #else 467 va.va_mask = AT_ALL; 468 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 469 #endif 470 471 VN_RELE(vp); 472 473 resp->status = NFS3_OK; 474 vattr_to_post_op_attr(vap, &resp->resok.attr); 475 if (!(args->mask & NA_ACL)) { 476 if (resp->resok.acl.vsa_aclcnt > 0 && 477 resp->resok.acl.vsa_aclentp != NULL) { 478 kmem_free((caddr_t)resp->resok.acl.vsa_aclentp, 479 resp->resok.acl.vsa_aclcnt * sizeof (aclent_t)); 480 } 481 resp->resok.acl.vsa_aclentp = NULL; 482 } 483 if (!(args->mask & NA_DFACL)) { 484 if (resp->resok.acl.vsa_dfaclcnt > 0 && 485 resp->resok.acl.vsa_dfaclentp != NULL) { 486 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 487 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 488 } 489 resp->resok.acl.vsa_dfaclentp = NULL; 490 } 491 return; 492 493 out: 494 if (curthread->t_flag & T_WOULDBLOCK) { 495 curthread->t_flag &= ~T_WOULDBLOCK; 496 resp->status = NFS3ERR_JUKEBOX; 497 } else 498 resp->status = puterrno3(error); 499 out1: 500 if (vp != NULL) 501 VN_RELE(vp); 502 vattr_to_post_op_attr(vap, &resp->resfail.attr); 503 } 504 505 fhandle_t * 506 acl3_getacl_getfh(GETACL3args *args) 507 { 508 509 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 510 } 511 512 void 513 acl3_getacl_free(GETACL3res *resp) 514 { 515 516 if (resp->status == NFS3_OK) { 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 if (resp->resok.acl.vsa_dfaclcnt > 0 && 523 resp->resok.acl.vsa_dfaclentp != NULL) { 524 kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp, 525 resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t)); 526 } 527 } 528 } 529 530 /* ARGSUSED */ 531 void 532 acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi, 533 struct svc_req *req, cred_t *cr) 534 { 535 int error; 536 vnode_t *vp; 537 vattr_t *vap; 538 vattr_t va; 539 540 vap = NULL; 541 542 vp = nfs3_fhtovp(&args->fh, exi); 543 if (vp == NULL) { 544 error = ESTALE; 545 goto out1; 546 } 547 548 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 549 550 #ifdef DEBUG 551 if (rfs3_do_post_op_attr) { 552 va.va_mask = AT_ALL; 553 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 554 } else 555 vap = NULL; 556 #else 557 va.va_mask = AT_ALL; 558 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 559 #endif 560 561 if (rdonly(exi, req) || vn_is_readonly(vp)) { 562 resp->status = NFS3ERR_ROFS; 563 goto out1; 564 } 565 566 error = VOP_SETSECATTR(vp, &args->acl, 0, cr); 567 568 #ifdef DEBUG 569 if (rfs3_do_post_op_attr) { 570 va.va_mask = AT_ALL; 571 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 572 } else 573 vap = NULL; 574 #else 575 va.va_mask = AT_ALL; 576 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 577 #endif 578 579 if (error) 580 goto out; 581 582 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 583 VN_RELE(vp); 584 585 resp->status = NFS3_OK; 586 vattr_to_post_op_attr(vap, &resp->resok.attr); 587 return; 588 589 out: 590 if (curthread->t_flag & T_WOULDBLOCK) { 591 curthread->t_flag &= ~T_WOULDBLOCK; 592 resp->status = NFS3ERR_JUKEBOX; 593 } else 594 resp->status = puterrno3(error); 595 out1: 596 if (vp != NULL) { 597 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 598 VN_RELE(vp); 599 } 600 vattr_to_post_op_attr(vap, &resp->resfail.attr); 601 } 602 603 fhandle_t * 604 acl3_setacl_getfh(SETACL3args *args) 605 { 606 607 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 608 } 609 610 /* ARGSUSED */ 611 void 612 acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp, 613 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 614 { 615 int error; 616 int flags; 617 vnode_t *vp, *avp; 618 619 vp = nfs3_fhtovp(&args->fh, exi); 620 if (vp == NULL) { 621 resp->status = NFS3ERR_STALE; 622 return; 623 } 624 625 flags = LOOKUP_XATTR; 626 if (args->create) 627 flags |= CREATE_XATTR_DIR; 628 else { 629 ulong_t val = 0; 630 error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr); 631 if (!error && val == 0) { 632 VN_RELE(vp); 633 resp->status = NFS3ERR_NOENT; 634 return; 635 } 636 } 637 638 error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr); 639 if (!error && avp == vp) { /* lookup of "" on old FS? */ 640 error = EINVAL; 641 VN_RELE(avp); 642 } 643 if (!error) { 644 struct vattr va; 645 va.va_mask = AT_ALL; 646 error = rfs4_delegated_getattr(avp, &va, 0, cr); 647 if (!error) { 648 vattr_to_post_op_attr(&va, &resp->resok.attr); 649 error = makefh3(&resp->resok.fh, avp, exi); 650 } 651 VN_RELE(avp); 652 } 653 654 VN_RELE(vp); 655 656 if (error) { 657 resp->status = puterrno3(error); 658 return; 659 } 660 resp->status = NFS3_OK; 661 } 662 663 fhandle_t * 664 acl3_getxattrdir_getfh(GETXATTRDIR3args *args) 665 { 666 return ((fhandle_t *)&args->fh.fh3_u.nfs_fh3_i.fh3_i); 667 } 668