1 /* 2 * Copyright 2016 Chris Torek <torek@ixsystems.com> 3 * All rights reserved 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted providing that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <assert.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <errno.h> 31 #include <sys/types.h> 32 #include <sys/acl.h> 33 #include <sys/stat.h> 34 35 #include "lib9p.h" 36 #include "lib9p_impl.h" 37 #include "genacl.h" 38 #include "fid.h" 39 #include "log.h" 40 41 typedef int econvertfn(acl_entry_t, struct l9p_ace *); 42 43 #ifndef __APPLE__ 44 static struct l9p_acl *l9p_new_acl(uint32_t acetype, uint32_t aceasize); 45 static struct l9p_acl *l9p_growacl(struct l9p_acl *acl, uint32_t aceasize); 46 static int l9p_count_aces(acl_t sysacl); 47 static struct l9p_acl *l9p_sysacl_to_acl(int, acl_t, econvertfn *); 48 #endif 49 static bool l9p_ingroup(gid_t tid, gid_t gid, gid_t *gids, size_t ngids); 50 static int l9p_check_aces(int32_t mask, struct l9p_acl *acl, struct stat *st, 51 uid_t uid, gid_t gid, gid_t *gids, size_t ngids); 52 53 void 54 l9p_acl_free(struct l9p_acl *acl) 55 { 56 57 free(acl); 58 } 59 60 /* 61 * Is the given group ID tid (test-id) any of the gid's in agids? 62 */ 63 static bool 64 l9p_ingroup(gid_t tid, gid_t gid, gid_t *gids, size_t ngids) 65 { 66 size_t i; 67 68 if (tid == gid) 69 return (true); 70 for (i = 0; i < ngids; i++) 71 if (tid == gids[i]) 72 return (true); 73 return (false); 74 } 75 76 /* #define ACE_DEBUG */ 77 78 /* 79 * Note that NFSv4 tests are done on a "first match" basis. 80 * That is, we check each ACE sequentially until we run out 81 * of ACEs, or find something explicitly denied (DENIED!), 82 * or have cleared out all our attempt-something bits. Once 83 * we come across an ALLOW entry for the bits we're trying, 84 * we clear those from the bits we're still looking for, in 85 * the order they appear. 86 * 87 * The result is either "definitely allowed" (we cleared 88 * all the bits), "definitely denied" (we hit a deny with 89 * some or all of the bits), or "unspecified". We 90 * represent these three states as +1 (positive = yes = allow), 91 * -1 (negative = no = denied), or 0 (no strong answer). 92 * 93 * For our caller's convenience, if we are called with a 94 * mask of 0, we return 0 (no answer). 95 */ 96 static int 97 l9p_check_aces(int32_t mask, struct l9p_acl *acl, struct stat *st, 98 uid_t uid, gid_t gid, gid_t *gids, size_t ngids) 99 { 100 uint32_t i; 101 struct l9p_ace *ace; 102 #ifdef ACE_DEBUG 103 const char *acetype, *allowdeny; 104 bool show_tid; 105 #endif 106 bool match; 107 uid_t tid; 108 109 if (mask == 0) 110 return (0); 111 112 for (i = 0; mask != 0 && i < acl->acl_nace; i++) { 113 ace = &acl->acl_aces[i]; 114 switch (ace->ace_type) { 115 case L9P_ACET_ACCESS_ALLOWED: 116 case L9P_ACET_ACCESS_DENIED: 117 break; 118 default: 119 /* audit, alarm - ignore */ 120 continue; 121 } 122 #ifdef ACE_DEBUG 123 show_tid = false; 124 #endif 125 if (ace->ace_flags & L9P_ACEF_OWNER) { 126 #ifdef ACE_DEBUG 127 acetype = "OWNER@"; 128 #endif 129 match = st->st_uid == uid; 130 } else if (ace->ace_flags & L9P_ACEF_GROUP) { 131 #ifdef ACE_DEBUG 132 acetype = "GROUP@"; 133 #endif 134 match = l9p_ingroup(st->st_gid, gid, gids, ngids); 135 } else if (ace->ace_flags & L9P_ACEF_EVERYONE) { 136 #ifdef ACE_DEBUG 137 acetype = "EVERYONE@"; 138 #endif 139 match = true; 140 } else { 141 if (ace->ace_idsize != sizeof(tid)) 142 continue; 143 #ifdef ACE_DEBUG 144 show_tid = true; 145 #endif 146 memcpy(&tid, &ace->ace_idbytes, sizeof(tid)); 147 if (ace->ace_flags & L9P_ACEF_IDENTIFIER_GROUP) { 148 #ifdef ACE_DEBUG 149 acetype = "group"; 150 #endif 151 match = l9p_ingroup(tid, gid, gids, ngids); 152 } else { 153 #ifdef ACE_DEBUG 154 acetype = "user"; 155 #endif 156 match = tid == uid; 157 } 158 } 159 /* 160 * If this ACE applies to us, check remaining bits. 161 * If any of those bits also apply, check the type: 162 * DENY means "stop now", ALLOW means allow these bits 163 * and keep checking. 164 */ 165 #ifdef ACE_DEBUG 166 allowdeny = ace->ace_type == L9P_ACET_ACCESS_DENIED ? 167 "deny" : "allow"; 168 #endif 169 if (match && (ace->ace_mask & (uint32_t)mask) != 0) { 170 #ifdef ACE_DEBUG 171 if (show_tid) 172 L9P_LOG(L9P_DEBUG, 173 "ACE: %s %s %d: mask 0x%x ace_mask 0x%x", 174 allowdeny, acetype, (int)tid, 175 (u_int)mask, (u_int)ace->ace_mask); 176 else 177 L9P_LOG(L9P_DEBUG, 178 "ACE: %s %s: mask 0x%x ace_mask 0x%x", 179 allowdeny, acetype, 180 (u_int)mask, (u_int)ace->ace_mask); 181 #endif 182 if (ace->ace_type == L9P_ACET_ACCESS_DENIED) 183 return (-1); 184 mask &= ~ace->ace_mask; 185 #ifdef ACE_DEBUG 186 L9P_LOG(L9P_DEBUG, "clear 0x%x: now mask=0x%x", 187 (u_int)ace->ace_mask, (u_int)mask); 188 #endif 189 } else { 190 #ifdef ACE_DEBUG 191 if (show_tid) 192 L9P_LOG(L9P_DEBUG, 193 "ACE: SKIP %s %s %d: " 194 "match %d mask 0x%x ace_mask 0x%x", 195 allowdeny, acetype, (int)tid, 196 (int)match, (u_int)mask, 197 (u_int)ace->ace_mask); 198 else 199 L9P_LOG(L9P_DEBUG, 200 "ACE: SKIP %s %s: " 201 "match %d mask 0x%x ace_mask 0x%x", 202 allowdeny, acetype, 203 (int)match, (u_int)mask, 204 (u_int)ace->ace_mask); 205 #endif 206 } 207 } 208 209 /* Return 1 if access definitely granted. */ 210 #ifdef ACE_DEBUG 211 L9P_LOG(L9P_DEBUG, "ACE: end of ACEs, mask now 0x%x: %s", 212 mask, mask ? "no-definitive-answer" : "ALLOW"); 213 #endif 214 return (mask == 0 ? 1 : 0); 215 } 216 217 /* 218 * Test against ACLs. 219 * 220 * The return value is normally 0 (access allowed) or EPERM 221 * (access denied), so it could just be a boolean.... 222 * 223 * For "make new dir in dir" and "remove dir in dir", you must 224 * set the mask to test the directory permissions (not ADD_FILE but 225 * ADD_SUBDIRECTORY, and DELETE_CHILD). For "make new file in dir" 226 * you must set the opmask to test file ADD_FILE. 227 * 228 * The L9P_ACE_DELETE flag means "can delete this thing"; it's not 229 * clear whether it should override the parent directory's ACL if 230 * any. In our case it does not, but a caller may try 231 * L9P_ACE_DELETE_CHILD (separately, on its own) and then a 232 * (second, separate) L9P_ACE_DELETE, to make the permissions work 233 * as "or" instead of "and". 234 * 235 * Pass a NULL parent/pstat if they are not applicable, e.g., 236 * for doing operations on an existing file, such as reading or 237 * writing data or attributes. Pass in a null child/cstat if 238 * that's not applicable, such as creating a new file/dir. 239 * 240 * NB: it's probably wise to allow the owner of any file to update 241 * the ACLs of that file, but we leave that test to the caller. 242 */ 243 int l9p_acl_check_access(int32_t opmask, struct l9p_acl_check_args *args) 244 { 245 struct l9p_acl *parent, *child; 246 struct stat *pstat, *cstat; 247 int32_t pop, cop; 248 size_t ngids; 249 uid_t uid; 250 gid_t gid, *gids; 251 int panswer, canswer; 252 253 assert(opmask != 0); 254 parent = args->aca_parent; 255 pstat = args->aca_pstat; 256 child = args->aca_child; 257 cstat = args->aca_cstat; 258 uid = args->aca_uid; 259 gid = args->aca_gid; 260 gids = args->aca_groups; 261 ngids = args->aca_ngroups; 262 263 #ifdef ACE_DEBUG 264 L9P_LOG(L9P_DEBUG, 265 "l9p_acl_check_access: opmask=0x%x uid=%ld gid=%ld ngids=%zd", 266 (u_int)opmask, (long)uid, (long)gid, ngids); 267 #endif 268 /* 269 * If caller said "superuser semantics", check that first. 270 * Note that we apply them regardless of ACLs. 271 */ 272 if (uid == 0 && args->aca_superuser) 273 return (0); 274 275 /* 276 * If told to ignore ACLs and use only stat-based permissions, 277 * discard any non-NULL ACL pointers. 278 * 279 * This will need some fancying up when we support POSIX ACLs. 280 */ 281 if ((args->aca_aclmode & L9P_ACM_NFS_ACL) == 0) 282 parent = child = NULL; 283 284 assert(parent == NULL || parent->acl_acetype == L9P_ACLTYPE_NFSv4); 285 assert(parent == NULL || pstat != NULL); 286 assert(child == NULL || child->acl_acetype == L9P_ACLTYPE_NFSv4); 287 assert(child == NULL || cstat != NULL); 288 assert(pstat != NULL || cstat != NULL); 289 290 /* 291 * If the operation is UNLINK we should have either both ACLs 292 * or no ACLs, but we won't require that here. 293 * 294 * If a parent ACL is supplied, it's a directory by definition. 295 * Make sure we're allowed to do this there, whatever this is. 296 * If a child ACL is supplied, check it too. Note that the 297 * DELETE permission only applies in the child though, not 298 * in the parent, and the DELETE_CHILD only applies in the 299 * parent. 300 */ 301 pop = cop = opmask; 302 if (parent != NULL || pstat != NULL) { 303 /* 304 * Remove child-only bits from parent op and 305 * parent-only bits from child op. 306 * 307 * L9P_ACE_DELETE is child-only. 308 * 309 * L9P_ACE_DELETE_CHILD is parent-only, and three data 310 * access bits overlap with three directory access bits. 311 * We should have child==NULL && cstat==NULL, so the 312 * three data bits should be redundant, but it's 313 * both trivial and safest to remove them anyway. 314 */ 315 pop &= ~L9P_ACE_DELETE; 316 cop &= ~(L9P_ACE_DELETE_CHILD | L9P_ACE_LIST_DIRECTORY | 317 L9P_ACE_ADD_FILE | L9P_ACE_ADD_SUBDIRECTORY); 318 } else { 319 /* 320 * Remove child-only bits from parent op. We need 321 * not bother since we just found we have no parent 322 * and no pstat, and hence won't actually *use* pop. 323 * 324 * pop &= ~(L9P_ACE_READ_DATA | L9P_ACE_WRITE_DATA | 325 * L9P_ACE_APPEND_DATA); 326 */ 327 } 328 panswer = 0; 329 canswer = 0; 330 if (parent != NULL) 331 panswer = l9p_check_aces(pop, parent, pstat, 332 uid, gid, gids, ngids); 333 if (child != NULL) 334 canswer = l9p_check_aces(cop, child, cstat, 335 uid, gid, gids, ngids); 336 337 if (panswer || canswer) { 338 /* 339 * Got a definitive answer from parent and/or 340 * child ACLs. We're not quite done yet though. 341 */ 342 if (opmask == L9P_ACOP_UNLINK) { 343 /* 344 * For UNLINK, we can get an allow from child 345 * and deny from parent, or vice versa. It's 346 * not 100% clear how to handle the two-answer 347 * case. ZFS says that if either says "allow", 348 * we allow, and if both definitely say "deny", 349 * we deny. This makes sense, so we do that 350 * here for all cases, even "strict". 351 */ 352 if (panswer > 0 || canswer > 0) 353 return (0); 354 if (panswer < 0 && canswer < 0) 355 return (EPERM); 356 /* non-definitive answer from one! move on */ 357 } else { 358 /* 359 * Have at least one definitive answer, and 360 * should have only one; obey whichever 361 * one it is. 362 */ 363 if (panswer) 364 return (panswer < 0 ? EPERM : 0); 365 return (canswer < 0 ? EPERM : 0); 366 } 367 } 368 369 /* 370 * No definitive answer from ACLs alone. Check for ZFS style 371 * permissions checking and an "UNLINK" operation under ACLs. 372 * If so, find write-and-execute permission on parent. 373 * Note that WRITE overlaps with ADD_FILE -- that's ZFS's 374 * way of saying "allow write to dir" -- but EXECUTE is 375 * separate from LIST_DIRECTORY, so that's at least a little 376 * bit cleaner. 377 * 378 * Note also that only a definitive yes (both bits are 379 * explicitly allowed) results in granting unlink, and 380 * a definitive no (at least one bit explicitly denied) 381 * results in EPERM. Only "no answer" moves on. 382 */ 383 if ((args->aca_aclmode & L9P_ACM_ZFS_ACL) && 384 opmask == L9P_ACOP_UNLINK && parent != NULL) { 385 panswer = l9p_check_aces(L9P_ACE_ADD_FILE | L9P_ACE_EXECUTE, 386 parent, pstat, uid, gid, gids, ngids); 387 if (panswer) 388 return (panswer < 0 ? EPERM : 0); 389 } 390 391 /* 392 * No definitive answer from ACLs. 393 * 394 * Try POSIX style rwx permissions if allowed. This should 395 * be rare, occurring mainly when caller supplied no ACLs 396 * or set the mode to suppress them. 397 * 398 * The stat to check is the parent's if we don't have a child 399 * (i.e., this is a dir op), or if the DELETE_CHILD bit is set 400 * (i.e., this is an unlink or similar). Otherwise it's the 401 * child's. 402 */ 403 if (args->aca_aclmode & L9P_ACM_STAT_MODE) { 404 struct stat *st; 405 int rwx, bits; 406 407 rwx = l9p_ace_mask_to_rwx(opmask); 408 if ((st = cstat) == NULL || (opmask & L9P_ACE_DELETE_CHILD)) 409 st = pstat; 410 if (uid == st->st_uid) 411 bits = (st->st_mode >> 6) & 7; 412 else if (l9p_ingroup(st->st_gid, gid, gids, ngids)) 413 bits = (st->st_mode >> 3) & 7; 414 else 415 bits = st->st_mode & 7; 416 /* 417 * If all the desired bits are set, we're OK. 418 */ 419 if ((rwx & bits) == rwx) 420 return (0); 421 } 422 423 /* all methods have failed, return EPERM */ 424 return (EPERM); 425 } 426 427 /* 428 * Collapse fancy ACL operation mask down to simple Unix bits. 429 * 430 * Directory operations don't map that well. However, listing 431 * a directory really does require read permission, and adding 432 * or deleting files really does require write permission, so 433 * this is probably sufficient. 434 */ 435 int 436 l9p_ace_mask_to_rwx(int32_t opmask) 437 { 438 int rwx = 0; 439 440 if (opmask & 441 (L9P_ACE_READ_DATA | L9P_ACE_READ_NAMED_ATTRS | 442 L9P_ACE_READ_ATTRIBUTES | L9P_ACE_READ_ACL)) 443 rwx |= 4; 444 if (opmask & 445 (L9P_ACE_WRITE_DATA | L9P_ACE_APPEND_DATA | 446 L9P_ACE_ADD_FILE | L9P_ACE_ADD_SUBDIRECTORY | 447 L9P_ACE_DELETE | L9P_ACE_DELETE_CHILD | 448 L9P_ACE_WRITE_NAMED_ATTRS | L9P_ACE_WRITE_ATTRIBUTES | 449 L9P_ACE_WRITE_ACL)) 450 rwx |= 2; 451 if (opmask & L9P_ACE_EXECUTE) 452 rwx |= 1; 453 return (rwx); 454 } 455 456 #ifndef __APPLE__ 457 /* 458 * Allocate new ACL holder and ACEs. 459 */ 460 static struct l9p_acl * 461 l9p_new_acl(uint32_t acetype, uint32_t aceasize) 462 { 463 struct l9p_acl *ret; 464 size_t asize, size; 465 466 asize = aceasize * sizeof(struct l9p_ace); 467 size = sizeof(struct l9p_acl) + asize; 468 ret = malloc(size); 469 if (ret != NULL) { 470 ret->acl_acetype = acetype; 471 ret->acl_nace = 0; 472 ret->acl_aceasize = aceasize; 473 } 474 return (ret); 475 } 476 477 /* 478 * Expand ACL to accomodate more entries. 479 * 480 * Currently won't shrink, only grow, so it's a fast no-op until 481 * we hit the allocated size. After that, it's best to grow in 482 * big chunks, or this will be O(n**2). 483 */ 484 static struct l9p_acl * 485 l9p_growacl(struct l9p_acl *acl, uint32_t aceasize) 486 { 487 struct l9p_acl *tmp; 488 size_t asize, size; 489 490 if (acl->acl_aceasize < aceasize) { 491 asize = aceasize * sizeof(struct l9p_ace); 492 size = sizeof(struct l9p_acl) + asize; 493 tmp = realloc(acl, size); 494 if (tmp == NULL) 495 free(acl); 496 acl = tmp; 497 } 498 return (acl); 499 } 500 501 /* 502 * Annoyingly, there's no POSIX-standard way to count the number 503 * of ACEs in a system ACL other than to walk through them all. 504 * This is silly, but at least 2n is still O(n), and the walk is 505 * short. (If the system ACL mysteriously grows, we'll handle 506 * that OK via growacl(), too.) 507 */ 508 static int 509 l9p_count_aces(acl_t sysacl) 510 { 511 acl_entry_t entry; 512 uint32_t n; 513 int id; 514 515 id = ACL_FIRST_ENTRY; 516 for (n = 0; acl_get_entry(sysacl, id, &entry) == 1; n++) 517 id = ACL_NEXT_ENTRY; 518 519 return ((int)n); 520 } 521 522 /* 523 * Create ACL with ACEs from the given acl_t. We use the given 524 * convert function on each ACE. 525 */ 526 static struct l9p_acl * 527 l9p_sysacl_to_acl(int acetype, acl_t sysacl, econvertfn *convert) 528 { 529 struct l9p_acl *acl; 530 acl_entry_t entry; 531 uint32_t n; 532 int error, id; 533 534 acl = l9p_new_acl((uint32_t)acetype, (uint32_t)l9p_count_aces(sysacl)); 535 if (acl == NULL) 536 return (NULL); 537 id = ACL_FIRST_ENTRY; 538 for (n = 0;;) { 539 if (acl_get_entry(sysacl, id, &entry) != 1) 540 break; 541 acl = l9p_growacl(acl, n + 1); 542 if (acl == NULL) 543 return (NULL); 544 error = (*convert)(entry, &acl->acl_aces[n]); 545 id = ACL_NEXT_ENTRY; 546 if (error == 0) 547 n++; 548 } 549 acl->acl_nace = n; 550 return (acl); 551 } 552 #endif 553 554 #if defined(HAVE_POSIX_ACLS) && 0 /* not yet */ 555 struct l9p_acl * 556 l9p_posix_acl_to_acl(acl_t sysacl) 557 { 558 } 559 #endif 560 561 #if defined(HAVE_FREEBSD_ACLS) 562 static int 563 l9p_frombsdnfs4(acl_entry_t sysace, struct l9p_ace *ace) 564 { 565 acl_tag_t tag; /* e.g., USER_OBJ, GROUP, etc */ 566 acl_entry_type_t entry_type; /* e.g., allow/deny */ 567 acl_permset_t absdperm; 568 acl_flagset_t absdflag; 569 acl_perm_t bsdperm; /* e.g., READ_DATA */ 570 acl_flag_t bsdflag; /* e.g., FILE_INHERIT_ACE */ 571 uint32_t flags, mask; 572 int error; 573 uid_t uid, *aid; 574 575 error = acl_get_tag_type(sysace, &tag); 576 if (error == 0) 577 error = acl_get_entry_type_np(sysace, &entry_type); 578 if (error == 0) 579 error = acl_get_flagset_np(sysace, &absdflag); 580 if (error == 0) 581 error = acl_get_permset(sysace, &absdperm); 582 if (error) 583 return (error); 584 585 flags = 0; 586 uid = 0; 587 aid = NULL; 588 589 /* move user/group/everyone + id-is-group-id into flags */ 590 switch (tag) { 591 case ACL_USER_OBJ: 592 flags |= L9P_ACEF_OWNER; 593 break; 594 case ACL_GROUP_OBJ: 595 flags |= L9P_ACEF_GROUP; 596 break; 597 case ACL_EVERYONE: 598 flags |= L9P_ACEF_EVERYONE; 599 break; 600 case ACL_GROUP: 601 flags |= L9P_ACEF_IDENTIFIER_GROUP; 602 /* FALLTHROUGH */ 603 case ACL_USER: 604 aid = acl_get_qualifier(sysace); /* ugh, this malloc()s */ 605 if (aid == NULL) 606 return (ENOMEM); 607 uid = *(uid_t *)aid; 608 free(aid); 609 aid = &uid; 610 break; 611 default: 612 return (EINVAL); /* can't happen */ 613 } 614 615 switch (entry_type) { 616 617 case ACL_ENTRY_TYPE_ALLOW: 618 ace->ace_type = L9P_ACET_ACCESS_ALLOWED; 619 break; 620 621 case ACL_ENTRY_TYPE_DENY: 622 ace->ace_type = L9P_ACET_ACCESS_DENIED; 623 break; 624 625 case ACL_ENTRY_TYPE_AUDIT: 626 ace->ace_type = L9P_ACET_SYSTEM_AUDIT; 627 break; 628 629 case ACL_ENTRY_TYPE_ALARM: 630 ace->ace_type = L9P_ACET_SYSTEM_ALARM; 631 break; 632 633 default: 634 return (EINVAL); /* can't happen */ 635 } 636 637 /* transform remaining BSD flags to internal NFS-y form */ 638 bsdflag = *absdflag; 639 if (bsdflag & ACL_ENTRY_FILE_INHERIT) 640 flags |= L9P_ACEF_FILE_INHERIT_ACE; 641 if (bsdflag & ACL_ENTRY_DIRECTORY_INHERIT) 642 flags |= L9P_ACEF_DIRECTORY_INHERIT_ACE; 643 if (bsdflag & ACL_ENTRY_NO_PROPAGATE_INHERIT) 644 flags |= L9P_ACEF_NO_PROPAGATE_INHERIT_ACE; 645 if (bsdflag & ACL_ENTRY_INHERIT_ONLY) 646 flags |= L9P_ACEF_INHERIT_ONLY_ACE; 647 if (bsdflag & ACL_ENTRY_SUCCESSFUL_ACCESS) 648 flags |= L9P_ACEF_SUCCESSFUL_ACCESS_ACE_FLAG; 649 if (bsdflag & ACL_ENTRY_FAILED_ACCESS) 650 flags |= L9P_ACEF_FAILED_ACCESS_ACE_FLAG; 651 ace->ace_flags = flags; 652 653 /* 654 * Transform BSD permissions to ace_mask. Note that directory 655 * vs file bits are the same in both sets, so we don't need 656 * to worry about that, at least. 657 * 658 * There seem to be no BSD equivalents for WRITE_RETENTION 659 * and WRITE_RETENTION_HOLD. 660 */ 661 mask = 0; 662 bsdperm = *absdperm; 663 if (bsdperm & ACL_READ_DATA) 664 mask |= L9P_ACE_READ_DATA; 665 if (bsdperm & ACL_WRITE_DATA) 666 mask |= L9P_ACE_WRITE_DATA; 667 if (bsdperm & ACL_APPEND_DATA) 668 mask |= L9P_ACE_APPEND_DATA; 669 if (bsdperm & ACL_READ_NAMED_ATTRS) 670 mask |= L9P_ACE_READ_NAMED_ATTRS; 671 if (bsdperm & ACL_WRITE_NAMED_ATTRS) 672 mask |= L9P_ACE_WRITE_NAMED_ATTRS; 673 if (bsdperm & ACL_EXECUTE) 674 mask |= L9P_ACE_EXECUTE; 675 if (bsdperm & ACL_DELETE_CHILD) 676 mask |= L9P_ACE_DELETE_CHILD; 677 if (bsdperm & ACL_READ_ATTRIBUTES) 678 mask |= L9P_ACE_READ_ATTRIBUTES; 679 if (bsdperm & ACL_WRITE_ATTRIBUTES) 680 mask |= L9P_ACE_WRITE_ATTRIBUTES; 681 /* L9P_ACE_WRITE_RETENTION */ 682 /* L9P_ACE_WRITE_RETENTION_HOLD */ 683 /* 0x00800 */ 684 if (bsdperm & ACL_DELETE) 685 mask |= L9P_ACE_DELETE; 686 if (bsdperm & ACL_READ_ACL) 687 mask |= L9P_ACE_READ_ACL; 688 if (bsdperm & ACL_WRITE_ACL) 689 mask |= L9P_ACE_WRITE_ACL; 690 if (bsdperm & ACL_WRITE_OWNER) 691 mask |= L9P_ACE_WRITE_OWNER; 692 if (bsdperm & ACL_SYNCHRONIZE) 693 mask |= L9P_ACE_SYNCHRONIZE; 694 ace->ace_mask = mask; 695 696 /* fill in variable-size user or group ID bytes */ 697 if (aid == NULL) 698 ace->ace_idsize = 0; 699 else { 700 ace->ace_idsize = sizeof(uid); 701 memcpy(&ace->ace_idbytes[0], aid, sizeof(uid)); 702 } 703 704 return (0); 705 } 706 707 struct l9p_acl * 708 l9p_freebsd_nfsv4acl_to_acl(acl_t sysacl) 709 { 710 711 return (l9p_sysacl_to_acl(L9P_ACLTYPE_NFSv4, sysacl, l9p_frombsdnfs4)); 712 } 713 #endif 714 715 #if defined(HAVE_DARWIN_ACLS) && 0 /* not yet */ 716 struct l9p_acl * 717 l9p_darwin_nfsv4acl_to_acl(acl_t sysacl) 718 { 719 } 720 #endif 721