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