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