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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * The following naming convention is used in function names. 30 * 31 * If an argument is one or more aclent_t, we use "aent". 32 * If an argument is one or more nfsace4, we use "ace4". 33 * If an argument is one or more ace_t, we use "acet". 34 * 35 * If there is an aggregate of the one above... 36 * If it's contained in a vsecattr_t, we prepend "vs_". 37 * If it's contained in an "array" (pointer) and length, we prepend "ln_". 38 * 39 * Thus, for example, suppose you have a function that converts an 40 * array of aclent_t structures into an array of nfsace4 structures, 41 * it's name would be "ln_aent_to_ace4". 42 */ 43 44 #include <sys/acl.h> 45 #include <nfs/nfs4_kprot.h> 46 #include <nfs/nfs4.h> 47 #include <nfs/rnode4.h> 48 #include <sys/cmn_err.h> 49 #include <sys/systm.h> 50 #include <sys/sdt.h> 51 52 #define ACE4_POSIX_SUPPORTED_BITS (ACE4_READ_DATA | \ 53 ACE4_WRITE_DATA | \ 54 ACE4_APPEND_DATA | \ 55 ACE4_EXECUTE | \ 56 ACE4_READ_ATTRIBUTES | \ 57 ACE4_READ_ACL | \ 58 ACE4_WRITE_ACL) 59 60 static int ace4vals_compare(const void *, const void *); 61 static int nfs4_ace4_list_construct(void *, void *, int); 62 static void nfs4_ace4_list_destroy(void *, void *); 63 static void ace4_list_free(ace4_list_t *); 64 static void ace4vals_init(ace4vals_t *, utf8string *); 65 static void ace4_list_init(ace4_list_t *, int); 66 static int ln_aent_preprocess(aclent_t *, int, 67 int *, o_mode_t *, int *, int *, int *); 68 static void ace4_make_deny(nfsace4 *, nfsace4 *, int, int, int); 69 static acemask4 mode_to_ace4_access(o_mode_t, int, int, int, int); 70 static int ln_aent_to_ace4(aclent_t *, int, nfsace4 **, int *, int, int); 71 static int ace4_mask_to_mode(acemask4, o_mode_t *, int); 72 static int ace4_allow_to_mode(acemask4, o_mode_t *, int); 73 static ace4vals_t *ace4vals_find(nfsace4 *, avl_tree_t *, int *); 74 static int ace4_to_aent_legal(nfsace4 *, int); 75 static int ace4vals_to_aent(ace4vals_t *, aclent_t *, ace4_list_t *, 76 uid_t, gid_t, int, int, int); 77 static int ace4_list_to_aent(ace4_list_t *, aclent_t **, int *, uid_t, gid_t, 78 int, int, int); 79 static int ln_ace4_to_aent(nfsace4 *ace4, int n, uid_t, gid_t, 80 aclent_t **, int *, aclent_t **, int *, int, int, int); 81 static int ace4_cmp(nfsace4 *, nfsace4 *); 82 static int acet_to_ace4(ace_t *, nfsace4 *, int); 83 static int ace4_to_acet(nfsace4 *, ace_t *, uid_t, gid_t, int, int); 84 static int validate_idmapping(utf8string *, uid_t, int, int, int); 85 static int u8s_mapped_to_nobody(utf8string *, uid_t, int); 86 static void ace4_mask_to_acet_mask(acemask4, uint32_t *); 87 static void acet_mask_to_ace4_mask(uint32_t, acemask4 *); 88 static void ace4_flags_to_acet_flags(aceflag4, uint16_t *); 89 static void acet_flags_to_ace4_flags(uint16_t, aceflag4 *); 90 91 /* 92 * The following two functions check and set ACE4_SYNCRONIZE, ACE4_WRITE_OWNER, 93 * ACE4_DELETE and ACE4_WRITE_ATTRIBUTES. 94 */ 95 static int access_mask_check(nfsace4 *, int, int, int); 96 static acemask4 access_mask_set(int, int, int, int, int); 97 98 static int nfs4_acl_debug = 0; 99 100 #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 101 #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 102 #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 103 #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 104 105 #define ACL_WRITE_OWNER_SET_DENY 0x0000010 106 #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 107 #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 108 #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 109 110 #define ACL_DELETE_SET_DENY 0x0000100 111 #define ACL_DELETE_SET_ALLOW 0x0000200 112 #define ACL_DELETE_ERR_DENY 0x0000400 113 #define ACL_DELETE_ERR_ALLOW 0x0000800 114 115 #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 116 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 117 #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 118 #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 119 120 #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 121 #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 122 #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 123 #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 124 125 #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 126 #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 127 #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 128 #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 129 130 #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 131 #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 132 #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 133 #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 134 135 /* 136 * What we will send the server upon setting an ACL on our client 137 */ 138 static int nfs4_acl_client_produce = 139 (ACL_SYNCHRONIZE_SET_ALLOW | 140 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 141 ACL_WRITE_ATTRS_WRITER_SET_DENY); 142 143 /* 144 * What we will accept upon getting an ACL on our client 145 */ 146 static int nfs4_acl_client_consume = 147 (ACL_WRITE_OWNER_ERR_DENY | 148 ACL_WRITE_OWNER_ERR_ALLOW | 149 ACL_WRITE_ATTRS_OWNER_ERR_DENY | 150 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 151 ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 152 ACL_WRITE_ATTRS_WRITER_SET_DENY); 153 154 /* 155 * What we will produce as an ACL on a newly created file 156 */ 157 static int nfs4_acl_server_produce = 158 (ACL_SYNCHRONIZE_SET_ALLOW | 159 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 160 ACL_WRITE_ATTRS_WRITER_SET_DENY); 161 162 /* 163 * What we will accept upon setting an ACL on our server 164 */ 165 static int nfs4_acl_server_consume = 166 (ACL_SYNCHRONIZE_ERR_DENY | 167 ACL_DELETE_ERR_DENY | 168 ACL_WRITE_OWNER_ERR_DENY | 169 ACL_WRITE_OWNER_ERR_ALLOW | 170 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 171 ACL_WRITE_ATTRS_OWNER_ERR_DENY | 172 ACL_WRITE_ATTRS_WRITER_SET_DENY | 173 ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 174 ACL_WRITE_NAMED_WRITER_ERR_DENY | 175 ACL_READ_NAMED_READER_ERR_DENY); 176 177 static kmem_cache_t *nfs4_ace4vals_cache = NULL; 178 static kmem_cache_t *nfs4_ace4_list_cache = NULL; 179 180 static int 181 ace4vals_compare(const void *va, const void *vb) 182 { 183 const ace4vals_t *a = va, *b = vb; 184 185 if ((a->key == NULL) && (b->key == NULL)) 186 return (0); 187 else if (a->key == NULL) 188 return (-1); 189 else if (b->key == NULL) 190 return (1); 191 192 return (utf8_compare(a->key, b->key)); 193 } 194 195 /*ARGSUSED*/ 196 static int 197 nfs4_ace4_list_construct(void *voidp, void *arg, int kmem_flags) 198 { 199 ace4_list_t *a4l = voidp; 200 201 avl_create(&a4l->user, ace4vals_compare, sizeof (ace4vals_t), 202 offsetof(ace4vals_t, avl)); 203 avl_create(&a4l->group, ace4vals_compare, sizeof (ace4vals_t), 204 offsetof(ace4vals_t, avl)); 205 return (0); 206 } 207 208 /*ARGSUSED*/ 209 static void 210 nfs4_ace4_list_destroy(void *voidp, void *arg) 211 { 212 ace4_list_t *a4l = voidp; 213 214 avl_destroy(&a4l->user); 215 avl_destroy(&a4l->group); 216 } 217 218 void 219 nfs4_acl_init(void) 220 { 221 nfs4_ace4vals_cache = kmem_cache_create("nfs4_ace4vals_cache", 222 sizeof (ace4vals_t), 0, 223 NULL, NULL, 224 NULL, NULL, 225 NULL, 226 0); 227 nfs4_ace4_list_cache = kmem_cache_create("nfs4_ace4_list_cache", 228 sizeof (ace4_list_t), 0, 229 nfs4_ace4_list_construct, nfs4_ace4_list_destroy, 230 NULL, NULL, 231 NULL, 232 0); 233 } 234 235 void 236 vs_acet_destroy(vsecattr_t *vsp) 237 { 238 if (vsp->vsa_mask != (VSA_ACE | VSA_ACECNT)) 239 return; 240 241 if ((vsp->vsa_aclentp != NULL) && 242 (vsp->vsa_aclcnt > 0) && 243 (vsp->vsa_mask & VSA_ACE) && 244 (vsp->vsa_mask & VSA_ACECNT)) 245 kmem_free(vsp->vsa_aclentp, 246 vsp->vsa_aclcnt * sizeof (ace_t)); 247 248 vsp->vsa_aclentp = NULL; 249 vsp->vsa_aclcnt = 0; 250 } 251 252 void 253 vs_ace4_destroy(vsecattr_t *vsp) 254 { 255 nfsace4 *ace4; 256 int i; 257 258 if (vsp->vsa_mask != (VSA_ACE | VSA_ACECNT)) 259 return; 260 261 if ((vsp->vsa_aclentp != NULL) && 262 (vsp->vsa_aclcnt > 0) && 263 (vsp->vsa_mask & VSA_ACE) && 264 (vsp->vsa_mask & VSA_ACECNT)) { 265 for (i = 0; i < vsp->vsa_aclcnt; i++) { 266 ace4 = (nfsace4 *)vsp->vsa_aclentp + i; 267 if ((ace4->who.utf8string_len > 0) && 268 (ace4->who.utf8string_val != NULL)) 269 kmem_free(ace4->who.utf8string_val, 270 ace4->who.utf8string_len); 271 272 ace4->who.utf8string_val = NULL; 273 ace4->who.utf8string_len = 0; 274 } 275 276 kmem_free(vsp->vsa_aclentp, 277 vsp->vsa_aclcnt * sizeof (nfsace4)); 278 } 279 280 vsp->vsa_aclentp = NULL; 281 vsp->vsa_aclcnt = 0; 282 } 283 284 void 285 vs_aent_destroy(vsecattr_t *vsp) 286 { 287 if (vsp->vsa_mask & (VSA_ACE | VSA_ACECNT)) 288 return; 289 290 if ((vsp->vsa_aclentp != NULL) && 291 (vsp->vsa_aclcnt > 0) && 292 (vsp->vsa_mask & VSA_ACL) && 293 (vsp->vsa_mask & VSA_ACLCNT)) 294 kmem_free(vsp->vsa_aclentp, 295 vsp->vsa_aclcnt * sizeof (aclent_t)); 296 if ((vsp->vsa_dfaclentp != NULL) && 297 (vsp->vsa_dfaclcnt > 0) && 298 (vsp->vsa_mask & VSA_DFACL) && 299 (vsp->vsa_mask & VSA_DFACLCNT)) 300 kmem_free(vsp->vsa_dfaclentp, 301 vsp->vsa_dfaclcnt * sizeof (aclent_t)); 302 303 vsp->vsa_aclentp = NULL; 304 vsp->vsa_aclcnt = 0; 305 306 vsp->vsa_dfaclentp = NULL; 307 vsp->vsa_aclcnt = 0; 308 } 309 310 /* 311 * free all data associated with an ace4_list 312 */ 313 static void 314 ace4_list_free(ace4_list_t *a4l) 315 { 316 ace4vals_t *node; 317 void *cookie; 318 319 if (a4l == NULL) 320 return; 321 322 /* free all nodes, but don't destroy the trees themselves */ 323 cookie = NULL; 324 while ((node = avl_destroy_nodes(&a4l->user, &cookie)) != NULL) 325 kmem_cache_free(nfs4_ace4vals_cache, node); 326 cookie = NULL; 327 while ((node = avl_destroy_nodes(&a4l->group, &cookie)) != NULL) 328 kmem_cache_free(nfs4_ace4vals_cache, node); 329 330 /* free the container itself */ 331 kmem_cache_free(nfs4_ace4_list_cache, a4l); 332 } 333 334 static void 335 ace4vals_init(ace4vals_t *vals, utf8string *key) 336 { 337 bzero(vals, sizeof (*vals)); 338 vals->allowed = ACE4_MASK_UNDEFINED; 339 vals->denied = ACE4_MASK_UNDEFINED; 340 vals->mask = ACE4_MASK_UNDEFINED; 341 vals->key = key; 342 } 343 344 static void 345 ace4_list_init(ace4_list_t *a4l, int dfacl_flag) 346 { 347 ace4vals_init(&a4l->user_obj, NULL); 348 ace4vals_init(&a4l->group_obj, NULL); 349 ace4vals_init(&a4l->other_obj, NULL); 350 a4l->numusers = 0; 351 a4l->numgroups = 0; 352 a4l->acl_mask = 0; 353 a4l->hasmask = 0; 354 a4l->state = ace4_unused; 355 a4l->seen = 0; 356 a4l->dfacl_flag = dfacl_flag; 357 } 358 359 /* 360 * Make an initial pass over an array of aclent_t's. Gather 361 * information such as an ACL_MASK (if any), number of users, 362 * number of groups, and whether the array needs to be sorted. 363 */ 364 static int 365 ln_aent_preprocess(aclent_t *aclent, int n, 366 int *hasmask, o_mode_t *mask, 367 int *numuser, int *numgroup, int *needsort) 368 { 369 int error = 0; 370 int i; 371 int curtype = 0; 372 373 *hasmask = 0; 374 *mask = 07; 375 *needsort = 0; 376 *numuser = 0; 377 *numgroup = 0; 378 379 for (i = 0; i < n; i++) { 380 if (aclent[i].a_type < curtype) 381 *needsort = 1; 382 else if (aclent[i].a_type > curtype) 383 curtype = aclent[i].a_type; 384 if (aclent[i].a_type & USER) 385 (*numuser)++; 386 if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 387 (*numgroup)++; 388 if (aclent[i].a_type & CLASS_OBJ) { 389 if (*hasmask) { 390 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 391 "ln_aent_preprocess: multiple CLASS_OBJs " 392 "(masks) found")); 393 error = EINVAL; 394 goto out; 395 } else { 396 *hasmask = 1; 397 *mask = aclent[i].a_perm; 398 } 399 } 400 } 401 402 if ((! *hasmask) && (*numuser + *numgroup > 1)) { 403 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 404 "ln_aent_preprocess: no CLASS_OBJs " 405 "(masks) found")); 406 error = EINVAL; 407 goto out; 408 } 409 410 out: 411 return (error); 412 } 413 414 static acemask4 415 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow, 416 int isserver) 417 { 418 acemask4 access_mask = 0; 419 int nfs4_acl_produce; 420 int synchronize_set = 0, write_owner_set = 0; 421 int delete_set = 0, write_attrs_set = 0; 422 int read_named_set = 0, write_named_set = 0; 423 424 if (isserver) 425 nfs4_acl_produce = nfs4_acl_server_produce; 426 else 427 nfs4_acl_produce = nfs4_acl_client_produce; 428 429 if (isallow) { 430 synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 431 write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 432 delete_set = ACL_DELETE_SET_ALLOW; 433 if (hasreadperm) 434 read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 435 if (haswriteperm) 436 write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 437 if (isowner) 438 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 439 else if (haswriteperm) 440 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 441 } else { 442 synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 443 write_owner_set = ACL_WRITE_OWNER_SET_DENY; 444 delete_set = ACL_DELETE_SET_DENY; 445 if (hasreadperm) 446 read_named_set = ACL_READ_NAMED_READER_SET_DENY; 447 if (haswriteperm) 448 write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 449 if (isowner) 450 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 451 else if (haswriteperm) 452 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 453 else 454 /* 455 * If the entity is not the owner and does not 456 * have write permissions ACE4_WRITE_ATTRIBUTES will 457 * always go in the DENY ACE. 458 */ 459 access_mask |= ACE4_WRITE_ATTRIBUTES; 460 } 461 462 if (nfs4_acl_produce & synchronize_set) 463 access_mask |= ACE4_SYNCHRONIZE; 464 if (nfs4_acl_produce & write_owner_set) 465 access_mask |= ACE4_WRITE_OWNER; 466 if (nfs4_acl_produce & delete_set) 467 access_mask |= ACE4_DELETE; 468 if (nfs4_acl_produce & write_attrs_set) 469 access_mask |= ACE4_WRITE_ATTRIBUTES; 470 if (nfs4_acl_produce & read_named_set) 471 access_mask |= ACE4_READ_NAMED_ATTRS; 472 if (nfs4_acl_produce & write_named_set) 473 access_mask |= ACE4_WRITE_NAMED_ATTRS; 474 475 return (access_mask); 476 } 477 478 /* 479 * Given an nfsace4 (presumably an ALLOW entry), make a 480 * corresponding DENY entry at the address given. 481 */ 482 static void 483 ace4_make_deny(nfsace4 *allow, nfsace4 *deny, int isdir, int isowner, 484 int isserver) 485 { 486 bcopy(allow, deny, sizeof (nfsace4)); 487 488 (void) utf8_copy(&allow->who, &deny->who); 489 490 deny->type = ACE4_ACCESS_DENIED_ACE_TYPE; 491 deny->access_mask ^= ACE4_POSIX_SUPPORTED_BITS; 492 if (isdir) 493 deny->access_mask ^= ACE4_DELETE_CHILD; 494 495 deny->access_mask &= ~(ACE4_SYNCHRONIZE | ACE4_WRITE_OWNER | 496 ACE4_DELETE | ACE4_WRITE_ATTRIBUTES | ACE4_READ_NAMED_ATTRS | 497 ACE4_WRITE_NAMED_ATTRS); 498 deny->access_mask |= access_mask_set((allow->access_mask & 499 ACE4_WRITE_DATA), (allow->access_mask & ACE4_READ_DATA), isowner, 500 FALSE, isserver); 501 } 502 503 /* 504 * Given an o_mode_t, convert it into an access_mask as used 505 * by nfsace4, assuming aclent_t -> nfsace4 semantics. 506 */ 507 static acemask4 508 mode_to_ace4_access(o_mode_t mode, int isdir, int isowner, int isallow, 509 int isserver) 510 { 511 acemask4 access = 0; 512 int haswriteperm = 0; 513 int hasreadperm = 0; 514 515 if (isallow) { 516 haswriteperm = (mode & 02); 517 hasreadperm = (mode & 04); 518 } else { 519 haswriteperm = !(mode & 02); 520 hasreadperm = !(mode & 04); 521 } 522 523 /* 524 * The following call takes care of correctly setting the following 525 * mask bits in the access_mask: 526 * ACE4_SYNCHRONIZE, ACE4_WRITE_OWNER, ACE4_DELETE, 527 * ACE4_WRITE_ATTRIBUTES, ACE4_WRITE_NAMED_ATTRS, ACE4_READ_NAMED_ATTRS 528 */ 529 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow, 530 isserver); 531 532 if (isallow) { 533 access |= ACE4_READ_ACL | ACE4_READ_ATTRIBUTES; 534 if (isowner) 535 access |= ACE4_WRITE_ACL; 536 } else { 537 if (! isowner) 538 access |= ACE4_WRITE_ACL; 539 } 540 541 /* read */ 542 if (mode & 04) { 543 access |= ACE4_READ_DATA; 544 } 545 /* write */ 546 if (mode & 02) { 547 access |= ACE4_WRITE_DATA | 548 ACE4_APPEND_DATA; 549 if (isdir) 550 access |= ACE4_DELETE_CHILD; 551 } 552 /* exec */ 553 if (mode & 01) { 554 access |= ACE4_EXECUTE; 555 } 556 557 return (access); 558 } 559 560 /* 561 * Convert an array of aclent_t into an array of nfsace4 entries, 562 * following POSIX draft -> nfsv4 conversion semantics as outlined in 563 * the IETF draft. 564 */ 565 static int 566 ln_aent_to_ace4(aclent_t *aclent, int n, nfsace4 **acepp, int *rescount, 567 int isdir, int isserver) 568 { 569 int error = 0; 570 o_mode_t mask; 571 int numuser, numgroup, needsort; 572 int resultsize = 0; 573 int i, groupi = 0, skip; 574 nfsace4 *acep, *result = NULL; 575 int hasmask; 576 577 error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 578 &numuser, &numgroup, &needsort); 579 if (error != 0) 580 goto out; 581 582 /* allow + deny for each aclent */ 583 resultsize = n * 2; 584 if (hasmask) { 585 /* 586 * stick extra deny on the group_obj and on each 587 * user|group for the mask (the group_obj was added 588 * into the count for numgroup) 589 */ 590 resultsize += numuser + numgroup; 591 /* ... and don't count the mask itself */ 592 resultsize -= 2; 593 } 594 595 /* sort the source if necessary */ 596 if (needsort) 597 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 598 599 result = acep = kmem_zalloc(resultsize * sizeof (nfsace4), KM_SLEEP); 600 601 for (i = 0; i < n; i++) { 602 /* 603 * don't process CLASS_OBJ (mask); mask was grabbed in 604 * ln_aent_preprocess() 605 */ 606 if (aclent[i].a_type & CLASS_OBJ) 607 continue; 608 609 /* If we need an ACL_MASK emulator, prepend it now */ 610 if ((hasmask) && 611 (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 612 acep->type = ACE4_ACCESS_DENIED_ACE_TYPE; 613 acep->flag = 0; 614 if (aclent[i].a_type & GROUP_OBJ) { 615 (void) str_to_utf8(ACE4_WHO_GROUP, &acep->who); 616 acep->flag |= ACE4_IDENTIFIER_GROUP; 617 error = 0; 618 } else if (aclent[i].a_type & USER) { 619 error = nfs_idmap_uid_str(aclent[i].a_id, 620 &acep->who, isserver); 621 } else { 622 error = nfs_idmap_gid_str(aclent[i].a_id, 623 &acep->who, isserver); 624 acep->flag |= ACE4_IDENTIFIER_GROUP; 625 } 626 if (error != 0) { 627 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 628 "ln_aent_to_ace4: idmap translate " 629 "failed with %d", error)); 630 goto out; 631 } 632 if (aclent[i].a_type & ACL_DEFAULT) { 633 acep->flag |= ACE4_INHERIT_ONLY_ACE | 634 ACE4_FILE_INHERIT_ACE | 635 ACE4_DIRECTORY_INHERIT_ACE; 636 } 637 /* 638 * Set the access mask for the prepended deny 639 * ace. To do this, we invert the mask (found 640 * in ln_aent_preprocess()) then convert it to an 641 * DENY ace access_mask. 642 */ 643 acep->access_mask = mode_to_ace4_access((mask ^ 07), 644 isdir, 0, 0, isserver); 645 acep += 1; 646 } 647 648 /* handle a_perm -> access_mask */ 649 acep->access_mask = mode_to_ace4_access(aclent[i].a_perm, 650 isdir, aclent[i].a_type & USER_OBJ, 1, isserver); 651 652 /* emulate a default aclent */ 653 if (aclent[i].a_type & ACL_DEFAULT) { 654 acep->flag |= ACE4_INHERIT_ONLY_ACE | 655 ACE4_FILE_INHERIT_ACE | 656 ACE4_DIRECTORY_INHERIT_ACE; 657 } 658 659 /* 660 * handle a_perm and a_id 661 * 662 * this must be done last, since it involves the 663 * corresponding deny aces, which are handled 664 * differently for each different a_type. 665 */ 666 if (aclent[i].a_type & USER_OBJ) { 667 (void) str_to_utf8(ACE4_WHO_OWNER, &acep->who); 668 ace4_make_deny(acep, acep + 1, isdir, TRUE, isserver); 669 acep += 2; 670 } else if (aclent[i].a_type & USER) { 671 error = nfs_idmap_uid_str(aclent[i].a_id, &acep->who, 672 isserver); 673 if (error != 0) { 674 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 675 "ln_aent_to_ace4: uid idmap failed " 676 "with error %d", error)); 677 goto out; 678 } 679 ace4_make_deny(acep, acep + 1, isdir, FALSE, isserver); 680 acep += 2; 681 } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 682 if (aclent[i].a_type & GROUP_OBJ) { 683 (void) str_to_utf8(ACE4_WHO_GROUP, &acep->who); 684 error = 0; 685 } else { 686 error = nfs_idmap_gid_str(aclent[i].a_id, 687 &acep->who, isserver); 688 } 689 if (error != 0) { 690 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 691 "ln_aent_to_ace4: gid idmap failed " 692 "with error %d", error)); 693 goto out; 694 } 695 acep->flag |= ACE4_IDENTIFIER_GROUP; 696 /* 697 * Set the corresponding deny for the group ace. 698 * 699 * The deny aces go after all of the groups, unlike 700 * everything else, where they immediately follow 701 * the allow ace. 702 * 703 * We calculate "skip", the number of slots to 704 * skip ahead for the deny ace, here. 705 * 706 * The pattern is: 707 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 708 * thus, skip is 709 * (2 * numgroup) - 1 - groupi 710 * (2 * numgroup) to account for MD + A 711 * - 1 to account for the fact that we're on the 712 * access (A), not the mask (MD) 713 * - groupi to account for the fact that we have 714 * passed up groupi number of MD's. 715 */ 716 skip = (2 * numgroup) - 1 - groupi; 717 ace4_make_deny(acep, acep + skip, isdir, FALSE, 718 isserver); 719 /* 720 * If we just did the last group, skip acep past 721 * all of the denies; else, just move ahead one. 722 */ 723 if (++groupi >= numgroup) 724 acep += numgroup + 1; 725 else 726 acep += 1; 727 } else if (aclent[i].a_type & OTHER_OBJ) { 728 (void) str_to_utf8(ACE4_WHO_EVERYONE, &acep->who); 729 ace4_make_deny(acep, acep + 1, isdir, FALSE, isserver); 730 acep += 2; 731 } else { 732 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 733 "ln_aent_to_ace4: aclent_t with invalid type: %x", 734 aclent[i].a_type)); 735 error = EINVAL; 736 goto out; 737 } 738 } 739 740 *acepp = result; 741 *rescount = resultsize; 742 743 out: 744 745 if (error != 0) { 746 if ((result != NULL) && (resultsize > 0)) { 747 /* free any embedded "who" strings */ 748 for (i = 0; i < resultsize; i++) { 749 acep = result + i; 750 if ((acep->who.utf8string_len > 0) && 751 (acep->who.utf8string_val != NULL)) { 752 kmem_free(acep->who.utf8string_val, 753 acep->who.utf8string_len); 754 } 755 } 756 757 /* free the nfsace4 block */ 758 kmem_free(result, resultsize * sizeof (nfsace4)); 759 } 760 } 761 762 return (error); 763 } 764 765 /* 766 * Convert a POSIX draft ACL (in a vsecattr_t) to an NFSv4 ACL, following 767 * the semantics of the IETF draft, draft-ietf-nfsv4-acl-mapping-01.txt. 768 */ 769 int 770 vs_aent_to_ace4(vsecattr_t *aclentacl, vsecattr_t *vs_ace4, 771 int isdir, int isserver) 772 { 773 int error = 0; 774 nfsace4 *acebuf = NULL; 775 int acecnt = 0; 776 nfsace4 *dfacebuf = NULL; 777 int dfacecnt = 0; 778 779 /* initialize vs_ace4 in case we can't complete our work */ 780 vs_ace4->vsa_mask = 0; 781 vs_ace4->vsa_aclentp = NULL; 782 vs_ace4->vsa_aclcnt = 0; 783 vs_ace4->vsa_dfaclentp = NULL; 784 vs_ace4->vsa_dfaclcnt = 0; 785 786 if (! (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT | 787 VSA_DFACL | VSA_DFACLCNT))) { 788 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 789 "vs_aent_to_ace4: vsa_mask lacking proper mask")); 790 error = EINVAL; 791 goto out; 792 } 793 794 if ((aclentacl->vsa_aclcnt < 3) && 795 (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT))) { 796 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 797 "vs_aent_to_ace4: too small vsa_aclcnt, %d", 798 aclentacl->vsa_aclcnt)); 799 error = EINVAL; 800 goto out; 801 } 802 803 if ((aclentacl->vsa_dfaclcnt != 0) && (aclentacl->vsa_dfaclcnt < 3) && 804 (aclentacl->vsa_mask & (VSA_DFACL | VSA_DFACLCNT))) { 805 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 806 "vs_aent_to_ace4: too small vsa_dfaclcnt, %d", 807 aclentacl->vsa_dfaclcnt)); 808 error = EINVAL; 809 goto out; 810 } 811 812 if (aclentacl->vsa_aclcnt > 0) { 813 error = ln_aent_to_ace4(aclentacl->vsa_aclentp, 814 aclentacl->vsa_aclcnt, &acebuf, &acecnt, 815 isdir, isserver); 816 if (error != 0) 817 goto out; 818 } 819 if (aclentacl->vsa_dfaclcnt > 0) { 820 error = ln_aent_to_ace4(aclentacl->vsa_dfaclentp, 821 aclentacl->vsa_dfaclcnt, &dfacebuf, &dfacecnt, 822 isdir, isserver); 823 if (error != 0) 824 goto out; 825 } 826 827 vs_ace4->vsa_aclcnt = acecnt + dfacecnt; 828 /* on error, this is freed by vs_ace4_destroy() */ 829 if (vs_ace4->vsa_aclcnt > 0) 830 vs_ace4->vsa_aclentp = kmem_zalloc(vs_ace4->vsa_aclcnt * 831 sizeof (nfsace4), KM_SLEEP); 832 /* 833 * When we bcopy the nfsace4's, the result (in vsa_aclentp) 834 * will have its "who.utf8string_val" pointer pointing to the 835 * allocated strings. Thus, when we free acebuf and dbacebuf, 836 * we don't need to free these strings. 837 */ 838 if (acecnt > 0) 839 bcopy(acebuf, vs_ace4->vsa_aclentp, acecnt * sizeof (nfsace4)); 840 if (dfacecnt > 0) 841 bcopy(dfacebuf, (nfsace4 *) vs_ace4->vsa_aclentp + acecnt, 842 dfacecnt * sizeof (nfsace4)); 843 vs_ace4->vsa_mask = VSA_ACE | VSA_ACECNT; 844 845 out: 846 if (error != 0) 847 vs_ace4_destroy(vs_ace4); 848 849 if (acebuf != NULL) 850 kmem_free(acebuf, acecnt * sizeof (nfsace4)); 851 if (dfacebuf != NULL) 852 kmem_free(dfacebuf, dfacecnt * sizeof (nfsace4)); 853 854 return (error); 855 } 856 857 static int 858 ace4_mask_to_mode(acemask4 mask, o_mode_t *modep, int isdir) 859 { 860 int error = 0; 861 o_mode_t mode = 0; 862 acemask4 bits, wantbits; 863 864 /* read */ 865 if (mask & ACE4_READ_DATA) 866 mode |= 04; 867 868 /* write */ 869 wantbits = (ACE4_WRITE_DATA | 870 ACE4_APPEND_DATA); 871 if (isdir) 872 wantbits |= ACE4_DELETE_CHILD; 873 bits = mask & wantbits; 874 if (bits != 0) { 875 if (bits != wantbits) { 876 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 877 "ace4_mask_to_mode: bad subset of write flags " 878 "%x", bits)); 879 error = ENOTSUP; 880 goto out; 881 } 882 mode |= 02; 883 } 884 885 /* exec */ 886 if (mask & ACE4_EXECUTE) { 887 mode |= 01; 888 } 889 890 *modep = mode; 891 892 out: 893 return (error); 894 } 895 896 static int 897 ace4_allow_to_mode(acemask4 mask, o_mode_t *modep, int isdir) 898 { 899 /* ACE4_READ_ACL and ACE4_READ_ATTRIBUTES must both be set */ 900 if ((mask & (ACE4_READ_ACL | ACE4_READ_ATTRIBUTES)) != 901 (ACE4_READ_ACL | ACE4_READ_ATTRIBUTES)) { 902 return (ENOTSUP); 903 } 904 905 return (ace4_mask_to_mode(mask, modep, isdir)); 906 } 907 908 /* 909 * Find or create an ace4vals holder for a given id and avl tree. 910 * 911 * Note that only one thread will ever touch these avl trees, so 912 * there is no need for locking. 913 */ 914 static ace4vals_t * 915 ace4vals_find(nfsace4 *ace4, avl_tree_t *avl, int *num) 916 { 917 ace4vals_t key, *rc; 918 avl_index_t where; 919 920 key.key = &ace4->who; 921 rc = avl_find(avl, &key, &where); 922 if (rc != NULL) 923 return (rc); 924 925 /* this memory is freed by ln_ace4_to_aent()->ace4_list_free() */ 926 rc = kmem_cache_alloc(nfs4_ace4vals_cache, KM_SLEEP); 927 ace4vals_init(rc, &ace4->who); 928 avl_insert(avl, rc, where); 929 (*num)++; 930 931 return (rc); 932 } 933 934 static int 935 access_mask_check(nfsace4 *ace4p, int mask_bit, int isserver, int isowner) 936 { 937 int set_deny, err_deny; 938 int set_allow, err_allow; 939 int nfs4_acl_consume; 940 int haswriteperm, hasreadperm; 941 942 if (ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) { 943 haswriteperm = (ace4p->access_mask & ACE4_WRITE_DATA) ? 0 : 1; 944 hasreadperm = (ace4p->access_mask & ACE4_READ_DATA) ? 0 : 1; 945 } else { 946 haswriteperm = (ace4p->access_mask & ACE4_WRITE_DATA) ? 1 : 0; 947 hasreadperm = (ace4p->access_mask & ACE4_READ_DATA) ? 1 : 0; 948 } 949 950 if (isserver) 951 nfs4_acl_consume = nfs4_acl_server_consume; 952 else 953 nfs4_acl_consume = nfs4_acl_client_consume; 954 955 if (mask_bit == ACE4_SYNCHRONIZE) { 956 set_deny = ACL_SYNCHRONIZE_SET_DENY; 957 err_deny = ACL_SYNCHRONIZE_ERR_DENY; 958 set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 959 err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 960 } else if (mask_bit == ACE4_WRITE_OWNER) { 961 set_deny = ACL_WRITE_OWNER_SET_DENY; 962 err_deny = ACL_WRITE_OWNER_ERR_DENY; 963 set_allow = ACL_WRITE_OWNER_SET_ALLOW; 964 err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 965 } else if (mask_bit == ACE4_DELETE) { 966 set_deny = ACL_DELETE_SET_DENY; 967 err_deny = ACL_DELETE_ERR_DENY; 968 set_allow = ACL_DELETE_SET_ALLOW; 969 err_allow = ACL_DELETE_ERR_ALLOW; 970 } else if (mask_bit == ACE4_WRITE_ATTRIBUTES) { 971 if (isowner) { 972 set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 973 err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 974 set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 975 err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 976 } else if (haswriteperm) { 977 set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 978 err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 979 set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 980 err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 981 } else { 982 if ((ace4p->access_mask & mask_bit) && 983 (ace4p->type & ACE4_ACCESS_ALLOWED_ACE_TYPE)) { 984 return (ENOTSUP); 985 } 986 return (0); 987 } 988 } else if (mask_bit == ACE4_READ_NAMED_ATTRS) { 989 if (!hasreadperm) 990 return (0); 991 992 set_deny = ACL_READ_NAMED_READER_SET_DENY; 993 err_deny = ACL_READ_NAMED_READER_ERR_DENY; 994 set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 995 err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 996 } else if (mask_bit == ACE4_WRITE_NAMED_ATTRS) { 997 if (!haswriteperm) 998 return (0); 999 1000 set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 1001 err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 1002 set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 1003 err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 1004 } else 1005 return (EINVAL); 1006 1007 if (ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) { 1008 if (nfs4_acl_consume & set_deny) { 1009 if (!(ace4p->access_mask & mask_bit)) { 1010 return (ENOTSUP); 1011 } 1012 } else if (nfs4_acl_consume & err_deny) { 1013 if (ace4p->access_mask & mask_bit) { 1014 return (ENOTSUP); 1015 } 1016 } 1017 } else { 1018 /* ACE4_ACCESS_ALLOWED_ACE_TYPE */ 1019 if (nfs4_acl_consume & set_allow) { 1020 if (!(ace4p->access_mask & mask_bit)) { 1021 return (ENOTSUP); 1022 } 1023 } else if (nfs4_acl_consume & err_allow) { 1024 if (ace4p->access_mask & mask_bit) { 1025 return (ENOTSUP); 1026 } 1027 } 1028 } 1029 return (0); 1030 } 1031 1032 static int 1033 ace4_to_aent_legal(nfsace4 *ace4p, int isserver) 1034 { 1035 int error = 0; 1036 int isowner; 1037 1038 /* check for NULL who string */ 1039 if (ace4p->who.utf8string_val == NULL) { 1040 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1041 "ace4_to_aent_legal: NULL who string")); 1042 error = EINVAL; 1043 goto out; 1044 } 1045 1046 /* only ALLOW or DENY */ 1047 if ((ace4p->type != ACE4_ACCESS_ALLOWED_ACE_TYPE) && 1048 (ace4p->type != ACE4_ACCESS_DENIED_ACE_TYPE)) { 1049 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1050 "ace4_to_aent_legal: neither allow nor deny")); 1051 error = ENOTSUP; 1052 goto out; 1053 } 1054 1055 /* check for invalid flags */ 1056 if (ace4p->flag & ~(ACE4_VALID_FLAG_BITS)) { 1057 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1058 "ace4_to_aent_legal: invalid flags: %x", ace4p->flag)); 1059 error = EINVAL; 1060 goto out; 1061 } 1062 1063 /* some flags are illegal */ 1064 if (ace4p->flag & (ACE4_SUCCESSFUL_ACCESS_ACE_FLAG | 1065 ACE4_FAILED_ACCESS_ACE_FLAG | 1066 ACE4_NO_PROPAGATE_INHERIT_ACE)) { 1067 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1068 "ace4_to_aent_legal: illegal flags: %x", ace4p->flag)); 1069 error = ENOTSUP; 1070 goto out; 1071 } 1072 1073 /* check for invalid masks */ 1074 if (ace4p->access_mask & ~(ACE4_VALID_MASK_BITS)) { 1075 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1076 "ace4_to_aent_legal: invalid mask: %x", 1077 ace4p->access_mask)); 1078 error = EINVAL; 1079 goto out; 1080 } 1081 1082 if ((ace4p->who.utf8string_len == 6) && 1083 (bcmp(ACE4_WHO_OWNER, ace4p->who.utf8string_val, 6) == 0)) { 1084 isowner = 1; 1085 } else { 1086 isowner = 0; 1087 } 1088 1089 error = access_mask_check(ace4p, ACE4_SYNCHRONIZE, isserver, isowner); 1090 if (error) 1091 goto out; 1092 1093 error = access_mask_check(ace4p, ACE4_WRITE_OWNER, isserver, isowner); 1094 if (error) 1095 goto out; 1096 1097 error = access_mask_check(ace4p, ACE4_DELETE, isserver, isowner); 1098 if (error) 1099 goto out; 1100 1101 error = access_mask_check(ace4p, ACE4_WRITE_ATTRIBUTES, isserver, 1102 isowner); 1103 if (error) 1104 goto out; 1105 1106 error = access_mask_check(ace4p, ACE4_READ_NAMED_ATTRS, isserver, 1107 isowner); 1108 if (error) 1109 goto out; 1110 1111 error = access_mask_check(ace4p, ACE4_WRITE_NAMED_ATTRS, isserver, 1112 isowner); 1113 if (error) 1114 goto out; 1115 1116 /* more detailed checking of masks */ 1117 if (ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) { 1118 if (! (ace4p->access_mask & ACE4_READ_ATTRIBUTES)) { 1119 error = ENOTSUP; 1120 goto out; 1121 } 1122 if ((ace4p->access_mask & ACE4_WRITE_DATA) && 1123 (! (ace4p->access_mask & ACE4_APPEND_DATA))) { 1124 error = ENOTSUP; 1125 goto out; 1126 } 1127 if ((! (ace4p->access_mask & ACE4_WRITE_DATA)) && 1128 (ace4p->access_mask & ACE4_APPEND_DATA)) { 1129 error = ENOTSUP; 1130 goto out; 1131 } 1132 } 1133 1134 /* ACL enforcement */ 1135 if ((ace4p->access_mask & ACE4_READ_ACL) && 1136 (ace4p->type != ACE4_ACCESS_ALLOWED_ACE_TYPE)) { 1137 error = ENOTSUP; 1138 goto out; 1139 } 1140 if (ace4p->access_mask & ACE4_WRITE_ACL) { 1141 if ((ace4p->type == ACE4_ACCESS_DENIED_ACE_TYPE) && 1142 (isowner)) { 1143 error = ENOTSUP; 1144 goto out; 1145 } 1146 if ((ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) && 1147 (! isowner)) { 1148 error = ENOTSUP; 1149 goto out; 1150 } 1151 } 1152 1153 out: 1154 return (error); 1155 } 1156 1157 static int 1158 ace4vals_to_aent(ace4vals_t *vals, aclent_t *dest, ace4_list_t *list, 1159 uid_t owner, gid_t group, int isdir, int isserver, int just_count) 1160 { 1161 int error; 1162 acemask4 flips = ACE4_POSIX_SUPPORTED_BITS; 1163 1164 if (isdir) 1165 flips |= ACE4_DELETE_CHILD; 1166 if (vals->allowed != (vals->denied ^ flips)) { 1167 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1168 "ace4vals_to_aent: mis-matched allow/deny pair: %x/%x", 1169 vals->allowed, vals->denied)); 1170 error = ENOTSUP; 1171 goto out; 1172 } 1173 if ((list->hasmask) && (list->acl_mask != vals->mask) && 1174 (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 1175 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1176 "ace4vals_to_aent: entry is missing mask")); 1177 error = ENOTSUP; 1178 goto out; 1179 } 1180 error = ace4_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 1181 if (error != 0) 1182 goto out; 1183 dest->a_type = vals->aent_type; 1184 if (dest->a_type & (USER | GROUP)) { 1185 if (dest->a_type & USER) 1186 error = nfs_idmap_str_uid(vals->key, &dest->a_id, 1187 isserver); 1188 else 1189 error = nfs_idmap_str_gid(vals->key, &dest->a_id, 1190 isserver); 1191 if (error != 0) { 1192 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1193 "ace4vals_to_aent: idmap failed with %d", error)); 1194 if (isserver && (error == EPERM)) 1195 error = NFS4ERR_BADOWNER; 1196 goto out; 1197 } 1198 1199 error = validate_idmapping(vals->key, dest->a_id, 1200 (dest->a_type & USER ? 1 : 0), isserver, just_count); 1201 if (error != 0) { 1202 goto out; 1203 } 1204 } else if (dest->a_type & USER_OBJ) { 1205 dest->a_id = owner; 1206 } else if (dest->a_type & GROUP_OBJ) { 1207 dest->a_id = group; 1208 } else if (dest->a_type & OTHER_OBJ) { 1209 dest->a_id = 0; 1210 } else { 1211 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1212 "ace4vals_to_aent: dest->a_type invalid: %x " 1213 "(internal error)", dest->a_type)); 1214 error = EINVAL; 1215 goto out; 1216 } 1217 1218 out: 1219 return (error); 1220 } 1221 1222 static int 1223 ace4_list_to_aent(ace4_list_t *list, aclent_t **aclentp, int *aclcnt, 1224 uid_t owner, gid_t group, int isdir, int isserver, int just_count) 1225 { 1226 int error = 0; 1227 aclent_t *aent, *result = NULL; 1228 ace4vals_t *vals; 1229 int resultcount; 1230 1231 if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 1232 (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 1233 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1234 "ace4_list_to_aent: required aclent_t entites " 1235 "missing")); 1236 error = ENOTSUP; 1237 goto out; 1238 } 1239 if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 1240 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1241 "ace4_list_to_aent: CLASS_OBJ (mask) missing")); 1242 error = ENOTSUP; 1243 goto out; 1244 } 1245 1246 resultcount = 3 + list->numusers + list->numgroups; 1247 /* 1248 * This must be the same condition as below, when we add the CLASS_OBJ 1249 * (aka ACL mask) 1250 */ 1251 if ((list->hasmask) || (! list->dfacl_flag)) 1252 resultcount += 1; 1253 1254 result = aent = kmem_alloc(resultcount * sizeof (aclent_t), KM_SLEEP); 1255 1256 /* USER_OBJ */ 1257 ASSERT(list->user_obj.aent_type & USER_OBJ); 1258 error = ace4vals_to_aent(&list->user_obj, aent, list, owner, group, 1259 isdir, isserver, just_count); 1260 1261 if (error != 0) 1262 goto out; 1263 ++aent; 1264 /* USER */ 1265 vals = NULL; 1266 for (vals = avl_first(&list->user); vals != NULL; 1267 vals = AVL_NEXT(&list->user, vals)) { 1268 ASSERT(vals->aent_type & USER); 1269 error = ace4vals_to_aent(vals, aent, list, owner, group, 1270 isdir, isserver, just_count); 1271 if (error != 0) 1272 goto out; 1273 ++aent; 1274 } 1275 /* GROUP_OBJ */ 1276 ASSERT(list->group_obj.aent_type & GROUP_OBJ); 1277 error = ace4vals_to_aent(&list->group_obj, aent, list, owner, group, 1278 isdir, isserver, just_count); 1279 if (error != 0) 1280 goto out; 1281 ++aent; 1282 /* GROUP */ 1283 vals = NULL; 1284 for (vals = avl_first(&list->group); vals != NULL; 1285 vals = AVL_NEXT(&list->group, vals)) { 1286 ASSERT(vals->aent_type & GROUP); 1287 error = ace4vals_to_aent(vals, aent, list, owner, group, 1288 isdir, isserver, just_count); 1289 if (error != 0) 1290 goto out; 1291 ++aent; 1292 } 1293 /* 1294 * CLASS_OBJ (aka ACL_MASK) 1295 * 1296 * An ACL_MASK is not fabricated if the ACL is a default ACL. 1297 * This is to follow UFS's behavior. 1298 */ 1299 if ((list->hasmask) || (! list->dfacl_flag)) { 1300 if (list->hasmask) { 1301 acemask4 flips = ACE4_POSIX_SUPPORTED_BITS; 1302 if (isdir) 1303 flips |= ACE4_DELETE_CHILD; 1304 error = ace4_mask_to_mode(list->acl_mask ^ flips, 1305 &aent->a_perm, isdir); 1306 if (error != 0) 1307 goto out; 1308 } else { 1309 /* fabricate the ACL_MASK from the group permissions */ 1310 error = ace4_mask_to_mode(list->group_obj.allowed, 1311 &aent->a_perm, isdir); 1312 if (error != 0) 1313 goto out; 1314 } 1315 aent->a_id = 0; 1316 aent->a_type = CLASS_OBJ | list->dfacl_flag; 1317 ++aent; 1318 } 1319 /* OTHER_OBJ */ 1320 ASSERT(list->other_obj.aent_type & OTHER_OBJ); 1321 error = ace4vals_to_aent(&list->other_obj, aent, list, owner, group, 1322 isdir, isserver, just_count); 1323 if (error != 0) 1324 goto out; 1325 ++aent; 1326 1327 *aclentp = result; 1328 *aclcnt = resultcount; 1329 1330 out: 1331 if (error != 0) { 1332 if (result != NULL) 1333 kmem_free(result, resultcount * sizeof (aclent_t)); 1334 } 1335 1336 return (error); 1337 } 1338 1339 /* 1340 * Convert a list of nfsace4 entries to equivalent regular and default 1341 * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 1342 */ 1343 static int 1344 ln_ace4_to_aent(nfsace4 *ace4, int n, 1345 uid_t owner, gid_t group, 1346 aclent_t **aclentp, int *aclcnt, 1347 aclent_t **dfaclentp, int *dfaclcnt, 1348 int isdir, int isserver, int just_count) 1349 { 1350 int error = 0; 1351 nfsace4 *ace4p; 1352 acemask4 bits; 1353 int i; 1354 ace4_list_t *normacl = NULL, *dfacl = NULL, *acl; 1355 ace4vals_t *vals; 1356 1357 *aclentp = NULL; 1358 *aclcnt = 0; 1359 *dfaclentp = NULL; 1360 *dfaclcnt = 0; 1361 1362 /* we need at least user_obj, group_obj, and other_obj */ 1363 if (n < 6) { 1364 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1365 "ln_ace4_to_aent: too few nfsace4 entries: %d", n)); 1366 error = ENOTSUP; 1367 goto out; 1368 } 1369 if (ace4 == NULL) { 1370 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1371 "ln_ace4_to_aent: NULL source")); 1372 error = EINVAL; 1373 goto out; 1374 } 1375 1376 normacl = kmem_cache_alloc(nfs4_ace4_list_cache, KM_SLEEP); 1377 ace4_list_init(normacl, 0); 1378 dfacl = kmem_cache_alloc(nfs4_ace4_list_cache, KM_SLEEP); 1379 ace4_list_init(dfacl, ACL_DEFAULT); 1380 1381 /* process every nfsace4... */ 1382 for (i = 0; i < n; i++) { 1383 ace4p = &ace4[i]; 1384 1385 /* rule out certain cases quickly */ 1386 error = ace4_to_aent_legal(ace4p, isserver); 1387 if (error != 0) 1388 goto out; 1389 1390 /* 1391 * Turn off these bits in order to not have to worry about 1392 * them when doing the checks for compliments. 1393 */ 1394 ace4p->access_mask &= ~(ACE4_WRITE_OWNER | ACE4_DELETE | 1395 ACE4_SYNCHRONIZE | ACE4_WRITE_ATTRIBUTES | 1396 ACE4_READ_NAMED_ATTRS | ACE4_WRITE_NAMED_ATTRS); 1397 1398 /* see if this should be a regular or default acl */ 1399 bits = ace4p->flag & 1400 (ACE4_INHERIT_ONLY_ACE | 1401 ACE4_FILE_INHERIT_ACE | 1402 ACE4_DIRECTORY_INHERIT_ACE); 1403 if (bits != 0) { 1404 /* all or nothing on these inherit bits */ 1405 if (bits != (ACE4_INHERIT_ONLY_ACE | 1406 ACE4_FILE_INHERIT_ACE | 1407 ACE4_DIRECTORY_INHERIT_ACE)) { 1408 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1409 "ln_ace4_to_aent: bad inherit flags " 1410 "%x", bits)); 1411 error = ENOTSUP; 1412 goto out; 1413 } 1414 acl = dfacl; 1415 } else { 1416 acl = normacl; 1417 } 1418 1419 if ((ace4p->who.utf8string_len == 6) && 1420 (bcmp(ACE4_WHO_OWNER, 1421 ace4p->who.utf8string_val, 6) == 0)) { 1422 if (acl->state > ace4_user_obj) { 1423 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1424 "ln_ace4_to_aent: OWNER@ found " 1425 "out of order")); 1426 error = ENOTSUP; 1427 goto out; 1428 } 1429 acl->state = ace4_user_obj; 1430 acl->seen |= USER_OBJ; 1431 vals = &acl->user_obj; 1432 vals->aent_type = USER_OBJ | acl->dfacl_flag; 1433 } else if ((ace4p->who.utf8string_len == 9) && 1434 (bcmp(ACE4_WHO_EVERYONE, ace4p->who.utf8string_val, 9) 1435 == 0)) { 1436 acl->state = ace4_other_obj; 1437 acl->seen |= OTHER_OBJ; 1438 vals = &acl->other_obj; 1439 vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1440 } else if ((ace4p->who.utf8string_len == 6) && 1441 (bcmp(ACE4_WHO_GROUP, ace4p->who.utf8string_val, 6) == 0)) { 1442 if (acl->state > ace4_group) { 1443 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1444 "ln_ace4_to_aent: group entry found " 1445 "out of order")); 1446 error = ENOTSUP; 1447 goto out; 1448 } 1449 acl->seen |= GROUP_OBJ; 1450 vals = &acl->group_obj; 1451 vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1452 acl->state = ace4_group; 1453 } else if (ace4p->flag & ACE4_IDENTIFIER_GROUP) { 1454 if (acl->state > ace4_group) { 1455 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1456 "ln_ace4_to_aent: group entry found " 1457 "out of order")); 1458 error = ENOTSUP; 1459 goto out; 1460 } 1461 acl->seen |= GROUP; 1462 vals = ace4vals_find(ace4p, &acl->group, 1463 &acl->numgroups); 1464 vals->aent_type = GROUP | acl->dfacl_flag; 1465 acl->state = ace4_group; 1466 } else { 1467 if (acl->state > ace4_user) { 1468 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1469 "ln_ace4_to_aent: user entry found " 1470 "out of order")); 1471 error = ENOTSUP; 1472 goto out; 1473 } 1474 acl->state = ace4_user; 1475 acl->seen |= USER; 1476 vals = ace4vals_find(ace4p, &acl->user, 1477 &acl->numusers); 1478 vals->aent_type = USER | acl->dfacl_flag; 1479 } 1480 ASSERT(acl->state > ace4_unused); 1481 1482 if (ace4p->type == ACE4_ACCESS_ALLOWED_ACE_TYPE) { 1483 /* no more than one allowed per aclent_t */ 1484 if (vals->allowed != ACE4_MASK_UNDEFINED) { 1485 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1486 "ln_ace4_to_aent: too many ALLOWs " 1487 "for one entity")); 1488 error = ENOTSUP; 1489 goto out; 1490 } 1491 vals->allowed = ace4p->access_mask; 1492 } else { 1493 /* 1494 * it's a DENY; if there was a previous DENY, it 1495 * must have been an ACL_MASK. 1496 */ 1497 if (vals->denied != ACE4_MASK_UNDEFINED) { 1498 /* ACL_MASK is for USER and GROUP only */ 1499 if ((acl->state != ace4_user) && 1500 (acl->state != ace4_group)) { 1501 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1502 "ln_ace4_to_aent: ACL_MASK-like " 1503 "DENY found on non-user/non-group " 1504 "entity")); 1505 error = ENOTSUP; 1506 goto out; 1507 } 1508 1509 if (! acl->hasmask) { 1510 acl->hasmask = 1; 1511 acl->acl_mask = vals->denied; 1512 /* check for mismatched ACL_MASK emulations */ 1513 } else if (acl->acl_mask != vals->denied) { 1514 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1515 "ln_ace4_to_aent: ACL_MASK " 1516 "mismatch")); 1517 error = ENOTSUP; 1518 goto out; 1519 } 1520 vals->mask = vals->denied; 1521 } 1522 vals->denied = ace4p->access_mask; 1523 } 1524 } 1525 1526 /* done collating; produce the aclent_t lists */ 1527 if (normacl->state != ace4_unused) { 1528 error = ace4_list_to_aent(normacl, aclentp, aclcnt, 1529 owner, group, isdir, isserver, just_count); 1530 if (error != 0) 1531 goto out; 1532 } 1533 if (dfacl->state != ace4_unused) { 1534 error = ace4_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1535 owner, group, isdir, isserver, just_count); 1536 if (error != 0) 1537 goto out; 1538 } 1539 1540 out: 1541 if (normacl != NULL) 1542 ace4_list_free(normacl); 1543 if (dfacl != NULL) 1544 ace4_list_free(dfacl); 1545 1546 return (error); 1547 } 1548 1549 /* 1550 * Convert an NFSv4 ACL (in a vsecattr_t) to a POSIX draft ACL, following 1551 * the semantics of NFSv4_to_POSIX.html. Contact fsh-group@sun.com to 1552 * obtain this document. 1553 */ 1554 int 1555 vs_ace4_to_aent(vsecattr_t *vs_ace4, vsecattr_t *vs_aent, 1556 uid_t owner, gid_t group, int isdir, int isserver, int just_count) 1557 { 1558 int error = 0; 1559 1560 error = ln_ace4_to_aent(vs_ace4->vsa_aclentp, vs_ace4->vsa_aclcnt, 1561 owner, group, 1562 (aclent_t **)&vs_aent->vsa_aclentp, &vs_aent->vsa_aclcnt, 1563 (aclent_t **)&vs_aent->vsa_dfaclentp, &vs_aent->vsa_dfaclcnt, 1564 isdir, isserver, just_count); 1565 if (error != 0) 1566 goto out; 1567 1568 vs_aent->vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT; 1569 if ((vs_aent->vsa_aclcnt == 0) && (vs_aent->vsa_dfaclcnt == 0)) { 1570 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1571 "vs_ace4_to_aent: neither ACL nor default ACL found")); 1572 error = ENOTSUP; 1573 goto out; 1574 } 1575 1576 out: 1577 if (error != 0) { 1578 if (vs_aent != NULL) 1579 vs_aent_destroy(vs_aent); 1580 } 1581 1582 return (error); 1583 } 1584 1585 /* 1586 * compare two ace4 acls 1587 */ 1588 1589 static int 1590 ace4_cmp(nfsace4 *a, nfsace4 *b) 1591 { 1592 if (a->type < b->type) 1593 return (-1); 1594 if (a->type > b->type) 1595 return (1); 1596 if (a->flag < b->flag) 1597 return (-1); 1598 if (a->flag > b->flag) 1599 return (1); 1600 if (a->access_mask < b->access_mask) 1601 return (-1); 1602 if (a->access_mask > b->access_mask) 1603 return (1); 1604 return (utf8_compare(&a->who, &b->who)); 1605 } 1606 1607 int 1608 ln_ace4_cmp(nfsace4 *a, nfsace4* b, int n) 1609 { 1610 int rc; 1611 int i; 1612 1613 for (i = 0; i < n; i++) { 1614 rc = ace4_cmp(a + i, b + i); 1615 if (rc != 0) 1616 return (rc); 1617 } 1618 return (0); 1619 } 1620 1621 /* 1622 * Convert an ace_t to an nfsace4; the primary difference being 1623 * strings versus integer uid/gids. 1624 */ 1625 static int 1626 acet_to_ace4(ace_t *ace, nfsace4 *nfsace4, int isserver) 1627 { 1628 int error = 0; 1629 1630 if (ace == NULL) { 1631 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1632 "acet_to_ace4: NULL source")); 1633 error = EINVAL; 1634 goto out; 1635 } 1636 if (nfsace4 == NULL) { 1637 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1638 "acet_to_ace4: NULL destination")); 1639 error = EINVAL; 1640 goto out; 1641 } 1642 1643 switch (ace->a_type) { 1644 case ACE_ACCESS_ALLOWED_ACE_TYPE: 1645 nfsace4->type = ACE4_ACCESS_ALLOWED_ACE_TYPE; 1646 break; 1647 case ACE_ACCESS_DENIED_ACE_TYPE: 1648 nfsace4->type = ACE4_ACCESS_DENIED_ACE_TYPE; 1649 break; 1650 default: 1651 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1652 "acet_to_ace4: unsupported type: %x", ace->a_type)); 1653 error = ENOTSUP; 1654 break; 1655 } 1656 if (error != 0) 1657 goto out; 1658 1659 acet_mask_to_ace4_mask(ace->a_access_mask, &nfsace4->access_mask); 1660 acet_flags_to_ace4_flags(ace->a_flags, &nfsace4->flag); 1661 1662 if (ace->a_flags & ACE_GROUP) { 1663 nfsace4->flag |= ACE4_IDENTIFIER_GROUP; 1664 (void) str_to_utf8(ACE4_WHO_GROUP, &nfsace4->who); 1665 } else if (ace->a_flags & ACE_IDENTIFIER_GROUP) { 1666 nfsace4->flag |= ACE4_IDENTIFIER_GROUP; 1667 error = nfs_idmap_gid_str(ace->a_who, &nfsace4->who, isserver); 1668 if (error != 0) 1669 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1670 "acet_to_ace4: idmap failed with %d", error)); 1671 } else if (ace->a_flags & ACE_OWNER) { 1672 (void) str_to_utf8(ACE4_WHO_OWNER, &nfsace4->who); 1673 } else if (ace->a_flags & ACE_EVERYONE) { 1674 (void) str_to_utf8(ACE4_WHO_EVERYONE, &nfsace4->who); 1675 } else { 1676 error = nfs_idmap_uid_str(ace->a_who, &nfsace4->who, isserver); 1677 if (error != 0) 1678 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1679 "acet_to_ace4: idmap failed with %d", error)); 1680 } 1681 1682 out: 1683 return (error); 1684 } 1685 1686 /* 1687 * Convert an nfsace4 to an ace_t, the primary difference being 1688 * integer uid/gids versus strings. 1689 */ 1690 static int 1691 ace4_to_acet(nfsace4 *nfsace4, ace_t *ace, uid_t owner, gid_t group, 1692 int isserver, int just_count) 1693 { 1694 int error = 0; 1695 1696 if (nfsace4 == NULL) { 1697 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1698 "ace4_to_acet: NULL source")); 1699 return (EINVAL); 1700 } 1701 if (ace == NULL) { 1702 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1703 "ace4_to_acet: NULL destination")); 1704 return (EINVAL); 1705 } 1706 1707 switch (nfsace4->type) { 1708 case ACE4_ACCESS_ALLOWED_ACE_TYPE: 1709 ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 1710 break; 1711 case ACE4_ACCESS_DENIED_ACE_TYPE: 1712 ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 1713 break; 1714 default: 1715 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1716 "ace4_to_acet: unsupported type: %x", nfsace4->type)); 1717 error = ENOTSUP; 1718 break; 1719 } 1720 if (error != 0) 1721 goto out; 1722 1723 if (nfsace4->flag & ~(ACE4_VALID_FLAG_BITS)) { 1724 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1725 "ace4_to_acet: invalid flags: %x", nfsace4->flag)); 1726 error = EINVAL; 1727 goto out; 1728 } 1729 1730 /* check for invalid masks */ 1731 if (nfsace4->access_mask & ~(ACE4_VALID_MASK_BITS)) { 1732 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1733 "ace4_to_acet: invalid mask: %x", nfsace4->access_mask)); 1734 error = EINVAL; 1735 goto out; 1736 } 1737 1738 ace4_mask_to_acet_mask(nfsace4->access_mask, &ace->a_access_mask); 1739 1740 if (nfsace4->flag & ~ACE_NFSV4_SUP_FLAGS) { 1741 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1742 "ace4_to_acet: unsupported flags: %x", nfsace4->flag)); 1743 error = ENOTSUP; 1744 goto out; 1745 } 1746 ace4_flags_to_acet_flags(nfsace4->flag, &ace->a_flags); 1747 1748 if ((nfsace4->who.utf8string_len == 6) && 1749 (bcmp(ACE4_WHO_GROUP, 1750 nfsace4->who.utf8string_val, 6)) == 0) { 1751 ace->a_who = group; 1752 ace->a_flags |= ACE_GROUP | ACE_IDENTIFIER_GROUP; 1753 } else if ((nfsace4->who.utf8string_len == 6) && 1754 (bcmp(ACE4_WHO_OWNER, 1755 nfsace4->who.utf8string_val, 6) == 0)) { 1756 ace->a_flags |= ACE_OWNER; 1757 ace->a_who = owner; 1758 } else if ((nfsace4->who.utf8string_len == 9) && 1759 (bcmp(ACE4_WHO_EVERYONE, 1760 nfsace4->who.utf8string_val, 9) == 0)) { 1761 ace->a_flags |= ACE_EVERYONE; 1762 ace->a_who = 0; 1763 } else if (nfsace4->flag & ACE4_IDENTIFIER_GROUP) { 1764 ace->a_flags |= ACE_IDENTIFIER_GROUP; 1765 error = nfs_idmap_str_gid(&nfsace4->who, 1766 &ace->a_who, isserver); 1767 if (error != 0) { 1768 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1769 "ace4_to_acet: idmap failed with %d", 1770 error)); 1771 if (isserver && (error == EPERM)) 1772 error = NFS4ERR_BADOWNER; 1773 goto out; 1774 } 1775 error = validate_idmapping(&nfsace4->who, 1776 ace->a_who, FALSE, isserver, just_count); 1777 if (error != 0) 1778 goto out; 1779 } else { 1780 error = nfs_idmap_str_uid(&nfsace4->who, 1781 &ace->a_who, isserver); 1782 if (error != 0) { 1783 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1784 "ace4_to_acet: idmap failed with %d", 1785 error)); 1786 if (isserver && (error == EPERM)) 1787 error = NFS4ERR_BADOWNER; 1788 goto out; 1789 } 1790 error = validate_idmapping(&nfsace4->who, 1791 ace->a_who, TRUE, isserver, just_count); 1792 if (error != 0) 1793 goto out; 1794 } 1795 1796 out: 1797 return (error); 1798 } 1799 1800 static void 1801 ace4_mask_to_acet_mask(acemask4 ace4_mask, uint32_t *acet_mask) 1802 { 1803 *acet_mask = 0; 1804 1805 if (ace4_mask & ACE4_READ_DATA) 1806 *acet_mask |= ACE_READ_DATA; 1807 if (ace4_mask & ACE4_WRITE_DATA) 1808 *acet_mask |= ACE_WRITE_DATA; 1809 if (ace4_mask & ACE4_APPEND_DATA) 1810 *acet_mask |= ACE_APPEND_DATA; 1811 if (ace4_mask & ACE4_READ_NAMED_ATTRS) 1812 *acet_mask |= ACE_READ_NAMED_ATTRS; 1813 if (ace4_mask & ACE4_WRITE_NAMED_ATTRS) 1814 *acet_mask |= ACE_WRITE_NAMED_ATTRS; 1815 if (ace4_mask & ACE4_EXECUTE) 1816 *acet_mask |= ACE_EXECUTE; 1817 if (ace4_mask & ACE4_DELETE_CHILD) 1818 *acet_mask |= ACE_DELETE_CHILD; 1819 if (ace4_mask & ACE4_READ_ATTRIBUTES) 1820 *acet_mask |= ACE_READ_ATTRIBUTES; 1821 if (ace4_mask & ACE4_WRITE_ATTRIBUTES) 1822 *acet_mask |= ACE_WRITE_ATTRIBUTES; 1823 if (ace4_mask & ACE4_DELETE) 1824 *acet_mask |= ACE_DELETE; 1825 if (ace4_mask & ACE4_READ_ACL) 1826 *acet_mask |= ACE_READ_ACL; 1827 if (ace4_mask & ACE4_WRITE_ACL) 1828 *acet_mask |= ACE_WRITE_ACL; 1829 if (ace4_mask & ACE4_WRITE_OWNER) 1830 *acet_mask |= ACE_WRITE_OWNER; 1831 if (ace4_mask & ACE4_SYNCHRONIZE) 1832 *acet_mask |= ACE_SYNCHRONIZE; 1833 } 1834 1835 static void 1836 acet_mask_to_ace4_mask(uint32_t acet_mask, acemask4 *ace4_mask) 1837 { 1838 *ace4_mask = 0; 1839 1840 if (acet_mask & ACE_READ_DATA) 1841 *ace4_mask |= ACE4_READ_DATA; 1842 if (acet_mask & ACE_WRITE_DATA) 1843 *ace4_mask |= ACE4_WRITE_DATA; 1844 if (acet_mask & ACE_APPEND_DATA) 1845 *ace4_mask |= ACE_APPEND_DATA; 1846 if (acet_mask & ACE4_READ_NAMED_ATTRS) 1847 *ace4_mask |= ACE_READ_NAMED_ATTRS; 1848 if (acet_mask & ACE_WRITE_NAMED_ATTRS) 1849 *ace4_mask |= ACE4_WRITE_NAMED_ATTRS; 1850 if (acet_mask & ACE_EXECUTE) 1851 *ace4_mask |= ACE4_EXECUTE; 1852 if (acet_mask & ACE_DELETE_CHILD) 1853 *ace4_mask |= ACE4_DELETE_CHILD; 1854 if (acet_mask & ACE_READ_ATTRIBUTES) 1855 *ace4_mask |= ACE4_READ_ATTRIBUTES; 1856 if (acet_mask & ACE_WRITE_ATTRIBUTES) 1857 *ace4_mask |= ACE4_WRITE_ATTRIBUTES; 1858 if (acet_mask & ACE_DELETE) 1859 *ace4_mask |= ACE4_DELETE; 1860 if (acet_mask & ACE_READ_ACL) 1861 *ace4_mask |= ACE4_READ_ACL; 1862 if (acet_mask & ACE_WRITE_ACL) 1863 *ace4_mask |= ACE4_WRITE_ACL; 1864 if (acet_mask & ACE_WRITE_OWNER) 1865 *ace4_mask |= ACE4_WRITE_OWNER; 1866 if (acet_mask & ACE_SYNCHRONIZE) 1867 *ace4_mask |= ACE4_SYNCHRONIZE; 1868 } 1869 1870 static void 1871 ace4_flags_to_acet_flags(aceflag4 ace4_flags, uint16_t *acet_flags) 1872 { 1873 *acet_flags = 0; 1874 1875 if (ace4_flags & ACE4_FILE_INHERIT_ACE) 1876 *acet_flags |= ACE_FILE_INHERIT_ACE; 1877 if (ace4_flags & ACE4_DIRECTORY_INHERIT_ACE) 1878 *acet_flags |= ACE_DIRECTORY_INHERIT_ACE; 1879 if (ace4_flags & ACE4_NO_PROPAGATE_INHERIT_ACE) 1880 *acet_flags |= ACE_NO_PROPAGATE_INHERIT_ACE; 1881 if (ace4_flags & ACE4_INHERIT_ONLY_ACE) 1882 *acet_flags |= ACE_INHERIT_ONLY_ACE; 1883 if (ace4_flags & ACE4_SUCCESSFUL_ACCESS_ACE_FLAG) 1884 *acet_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 1885 if (ace4_flags & ACE4_FAILED_ACCESS_ACE_FLAG) 1886 *acet_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 1887 /* ACE_IDENTIFIER_GROUP is handled in ace4_to_acet() */ 1888 } 1889 1890 static void 1891 acet_flags_to_ace4_flags(uint16_t acet_flags, aceflag4 *ace4_flags) 1892 { 1893 *ace4_flags = 0; 1894 1895 if (acet_flags & ACE_FILE_INHERIT_ACE) 1896 *ace4_flags |= ACE4_FILE_INHERIT_ACE; 1897 if (acet_flags & ACE_DIRECTORY_INHERIT_ACE) 1898 *ace4_flags |= ACE4_DIRECTORY_INHERIT_ACE; 1899 if (acet_flags & ACE_NO_PROPAGATE_INHERIT_ACE) 1900 *ace4_flags |= ACE4_NO_PROPAGATE_INHERIT_ACE; 1901 if (acet_flags & ACE_INHERIT_ONLY_ACE) 1902 *ace4_flags |= ACE4_INHERIT_ONLY_ACE; 1903 if (acet_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 1904 *ace4_flags |= ACE4_SUCCESSFUL_ACCESS_ACE_FLAG; 1905 if (acet_flags & ACE_FAILED_ACCESS_ACE_FLAG) 1906 *ace4_flags |= ACE4_FAILED_ACCESS_ACE_FLAG; 1907 /* ACE4_IDENTIFIER_GROUP is handled in acet_to_ace4() */ 1908 } 1909 1910 int 1911 vs_ace4_to_acet(vsecattr_t *vs_ace4, vsecattr_t *vs_acet, 1912 uid_t owner, gid_t group, int isserver, int just_count) 1913 { 1914 int error; 1915 int i; 1916 1917 if ((vs_ace4->vsa_mask & (VSA_ACE | VSA_ACECNT)) != 1918 (VSA_ACE | VSA_ACECNT)) 1919 return (EINVAL); 1920 if (vs_ace4->vsa_aclcnt < 0) 1921 return (EINVAL); 1922 if ((vs_ace4->vsa_aclcnt == 0) || (vs_ace4->vsa_aclentp == NULL)) 1923 return (0); 1924 1925 if (vs_ace4->vsa_aclcnt > 0) 1926 vs_acet->vsa_aclentp = kmem_alloc(vs_ace4->vsa_aclcnt * 1927 sizeof (ace_t), KM_SLEEP); 1928 else 1929 vs_acet->vsa_aclentp = NULL; 1930 vs_acet->vsa_aclcnt = vs_ace4->vsa_aclcnt; 1931 vs_acet->vsa_mask = VSA_ACE | VSA_ACECNT; 1932 1933 for (i = 0; i < vs_ace4->vsa_aclcnt; i++) { 1934 error = ace4_to_acet((nfsace4 *)(vs_ace4->vsa_aclentp) + i, 1935 (ace_t *)(vs_acet->vsa_aclentp) + i, owner, group, 1936 isserver, just_count); 1937 if (error != 0) 1938 goto out; 1939 } 1940 1941 out: 1942 if (error != 0) 1943 vs_acet_destroy(vs_acet); 1944 1945 return (error); 1946 } 1947 1948 int 1949 vs_acet_to_ace4(vsecattr_t *vs_acet, vsecattr_t *vs_ace4, 1950 int isserver) 1951 { 1952 int error = 0; 1953 int i; 1954 1955 if (! (vs_acet->vsa_mask & VSA_ACE)) { 1956 NFS4_DEBUG(nfs4_acl_debug, (CE_NOTE, 1957 "vs_acet_to_ace4: VSA_ACE missing from mask")); 1958 return (EINVAL); 1959 } 1960 1961 if (vs_acet->vsa_aclcnt > 0) 1962 vs_ace4->vsa_aclentp = kmem_zalloc(vs_acet->vsa_aclcnt * 1963 sizeof (nfsace4), KM_SLEEP); 1964 else 1965 vs_ace4->vsa_aclentp = NULL; 1966 vs_ace4->vsa_aclcnt = vs_acet->vsa_aclcnt; 1967 vs_ace4->vsa_mask = VSA_ACE | VSA_ACECNT; 1968 1969 for (i = 0; i < vs_acet->vsa_aclcnt; i++) { 1970 error = acet_to_ace4((ace_t *)(vs_acet->vsa_aclentp) + i, 1971 (nfsace4 *)(vs_ace4->vsa_aclentp) + i, isserver); 1972 if (error != 0) 1973 goto out; 1974 } 1975 1976 out: 1977 if (error != 0) 1978 vs_ace4_destroy(vs_ace4); 1979 1980 return (error); 1981 } 1982 1983 void 1984 nfs4_acl_fill_cache(rnode4_t *rp, vsecattr_t *vsap) 1985 { 1986 size_t aclsize; 1987 vsecattr_t *rvsap; 1988 nfsace4 *tmp_ace4, *ace4; 1989 int i; 1990 1991 mutex_enter(&rp->r_statelock); 1992 if (rp->r_secattr != NULL) 1993 rvsap = rp->r_secattr; 1994 else { 1995 rvsap = kmem_zalloc(sizeof (*rvsap), KM_NOSLEEP); 1996 if (rvsap == NULL) { 1997 mutex_exit(&rp->r_statelock); 1998 return; 1999 } 2000 rp->r_secattr = rvsap; 2001 } 2002 2003 if (vsap->vsa_mask & VSA_ACE) { 2004 if (rvsap->vsa_aclentp != NULL) { 2005 if (rvsap->vsa_aclcnt != vsap->vsa_aclcnt) { 2006 vs_ace4_destroy(rvsap); 2007 rvsap->vsa_aclentp = NULL; 2008 } else { 2009 /* 2010 * The counts are equal so we don't have to 2011 * destroy the acl entries because we'd only 2012 * have to re-allocate them, but we do have to 2013 * destroy all of the who utf8strings. 2014 * The acl that we are now filling the cache 2015 * with may have the same amount of entries as 2016 * what is currently cached, but those entries 2017 * may not be the same. 2018 */ 2019 ace4 = (nfsace4 *) rvsap->vsa_aclentp; 2020 for (i = 0; i < rvsap->vsa_aclcnt; i++) { 2021 if (ace4[i].who.utf8string_val != NULL) 2022 kmem_free( 2023 ace4[i].who.utf8string_val, 2024 ace4[i].who.utf8string_len); 2025 } 2026 } 2027 } 2028 if (vsap->vsa_aclcnt > 0) { 2029 aclsize = vsap->vsa_aclcnt * sizeof (nfsace4); 2030 2031 if (rvsap->vsa_aclentp == NULL) { 2032 rvsap->vsa_aclentp = kmem_alloc(aclsize, 2033 KM_SLEEP); 2034 } 2035 2036 bcopy(vsap->vsa_aclentp, rvsap->vsa_aclentp, aclsize); 2037 2038 tmp_ace4 = (nfsace4 *) vsap->vsa_aclentp; 2039 ace4 = (nfsace4 *) rvsap->vsa_aclentp; 2040 for (i = 0; i < vsap->vsa_aclcnt; i++) { 2041 (void) utf8_copy(&tmp_ace4[i].who, 2042 &ace4[i].who); 2043 } 2044 } 2045 rvsap->vsa_aclcnt = vsap->vsa_aclcnt; 2046 rvsap->vsa_mask |= VSA_ACE | VSA_ACECNT; 2047 } 2048 if (vsap->vsa_mask & VSA_ACECNT) { 2049 if (rvsap->vsa_aclentp != NULL) { 2050 /* 2051 * If the caller requested to only cache the 2052 * count, get rid of the acl whether or not the 2053 * counts are equal because it may be invalid. 2054 */ 2055 if (vsap->vsa_mask == VSA_ACECNT || 2056 rvsap->vsa_aclcnt != vsap->vsa_aclcnt) { 2057 vs_ace4_destroy(rvsap); 2058 rvsap->vsa_aclentp = NULL; 2059 rvsap->vsa_mask &= ~VSA_ACE; 2060 } 2061 } 2062 rvsap->vsa_aclcnt = vsap->vsa_aclcnt; 2063 rvsap->vsa_mask |= VSA_ACECNT; 2064 } 2065 mutex_exit(&rp->r_statelock); 2066 } 2067 2068 /* 2069 * This should ONLY be called on the ACL cache (rnode4_t.r_secattr). The cache 2070 * is stored as a nfsv4 acl meaning the vsecattr_t.vsa_aclentp is a list of 2071 * nfsace4 entries and vsecattr_t.vsa_dfaclentp is NULL or not populated. 2072 */ 2073 void 2074 nfs4_acl_free_cache(vsecattr_t *vsap) 2075 { 2076 if (vsap == NULL) 2077 return; 2078 2079 if (vsap->vsa_aclentp != NULL) 2080 vs_ace4_destroy(vsap); 2081 2082 kmem_free(vsap, sizeof (*vsap)); 2083 vsap = NULL; 2084 } 2085 2086 static int 2087 validate_idmapping(utf8string *orig_who, uid_t mapped_id, int isuser, 2088 int isserver, int just_count) 2089 { 2090 if (u8s_mapped_to_nobody(orig_who, mapped_id, isuser)) { 2091 if (isserver) { 2092 char *who = NULL; 2093 uint_t len = 0; 2094 2095 /* 2096 * This code path gets executed on the server 2097 * in the case that we are setting an ACL. 2098 * 2099 * We silently got our who value (who@domain) 2100 * mapped to "nobody" (possibly because the 2101 * nfsmapid daemon was unresponsive). 2102 * We NEVER want to silently map the user or 2103 * group to "nobody" as this could end up 2104 * wrongly giving access to user or group 2105 * "nobody" rather than the entity it was 2106 * meant for. 2107 */ 2108 who = utf8_to_str(orig_who, &len, NULL); 2109 DTRACE_PROBE1(nfs4__acl__nobody, char *, who); 2110 if (who != NULL) 2111 kmem_free(who, len); 2112 return (NFS4ERR_BADOWNER); 2113 } else { 2114 char *who = NULL; 2115 uint_t len = 0; 2116 /* CLIENT */ 2117 /* 2118 * This code path gets executed on the client 2119 * when we are getting an ACL. 2120 * 2121 * If the caller just requested the count 2122 * don't fail the request just because we 2123 * failed mapping the other portions of the 2124 * ACL. Things such as vn_createat expect it's 2125 * call to VOP_GETSECATTR (to get the 2126 * default acl count) to succeed in order to 2127 * create a file. 2128 * 2129 * If the caller requested more than the count, 2130 * return an error as we will not want to 2131 * silently map user or group to "nobody" 2132 * because of the semantics that an ACL 2133 * modification interface (i.e. - setfacl -m) 2134 * may use to modify an ACL (i.e. - get the ACL 2135 * then use it as a basis for setting the 2136 * modified ACL). 2137 */ 2138 who = utf8_to_str(orig_who, &len, NULL); 2139 if (just_count) { 2140 DTRACE_PROBE1(nfs4__acl__nobody, char *, who); 2141 if (who != NULL) 2142 kmem_free(who, len); 2143 return (0); 2144 } else { 2145 DTRACE_PROBE1(nfs4__acl__nobody, char *, who); 2146 if (who != NULL) 2147 kmem_free(who, len); 2148 return (EACCES); 2149 } 2150 } 2151 } 2152 return (0); 2153 } 2154 /* 2155 * Returns 1 if the who, utf8string was mapped to UID_NOBODY or GID_NOBODY. 2156 * Returns 0 if the who, utf8string was mapped correctly. 2157 */ 2158 static int 2159 u8s_mapped_to_nobody(utf8string *orig_who, uid_t mapped_id, int isuser) 2160 { 2161 if (orig_who->utf8string_len == 6 && 2162 bcmp("nobody", orig_who->utf8string_val, 6) == 0) 2163 return (0); 2164 2165 if (isuser) 2166 return (mapped_id == UID_NOBODY); 2167 2168 return (mapped_id == GID_NOBODY); 2169 } 2170