1 /*- 2 * Copyright (c) 2008 Edward Tomasz Napierała <trasz@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY 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, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * ACL support routines specific to NFSv4 access control lists. These are 29 * utility routines for code common across file systems implementing NFSv4 30 * ACLs. 31 */ 32 33 #ifdef _KERNEL 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/mount.h> 40 #include <sys/priv.h> 41 #include <sys/vnode.h> 42 #include <sys/errno.h> 43 #include <sys/stat.h> 44 #include <sys/acl.h> 45 #else 46 #include <errno.h> 47 #include <assert.h> 48 #include <sys/acl.h> 49 #include <sys/stat.h> 50 #define KASSERT(a, b) assert(a) 51 #define CTASSERT(a) 52 #endif 53 54 static int 55 _acl_entry_matches(struct acl_entry *entry, acl_tag_t tag, acl_perm_t perm, 56 acl_entry_type_t entry_type) 57 { 58 if (entry->ae_tag != tag) 59 return (0); 60 61 if (entry->ae_id != ACL_UNDEFINED_ID) 62 return (0); 63 64 if (entry->ae_perm != perm) 65 return (0); 66 67 if (entry->ae_entry_type != entry_type) 68 return (0); 69 70 if (entry->ae_flags != 0) 71 return (0); 72 73 return (1); 74 } 75 76 static struct acl_entry * 77 _acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm, 78 acl_entry_type_t entry_type) 79 { 80 struct acl_entry *entry; 81 82 KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 83 ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 84 85 entry = &(aclp->acl_entry[aclp->acl_cnt]); 86 aclp->acl_cnt++; 87 88 entry->ae_tag = tag; 89 entry->ae_id = ACL_UNDEFINED_ID; 90 entry->ae_perm = perm; 91 entry->ae_entry_type = entry_type; 92 entry->ae_flags = 0; 93 94 return (entry); 95 } 96 97 static struct acl_entry * 98 _acl_duplicate_entry(struct acl *aclp, int entry_index) 99 { 100 int i; 101 102 KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 103 ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 104 105 for (i = aclp->acl_cnt; i > entry_index; i--) 106 aclp->acl_entry[i] = aclp->acl_entry[i - 1]; 107 108 aclp->acl_cnt++; 109 110 return (&(aclp->acl_entry[entry_index + 1])); 111 } 112 113 void 114 acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id) 115 { 116 int i, meets, must_append; 117 struct acl_entry *entry, *copy, *previous, 118 *a1, *a2, *a3, *a4, *a5, *a6; 119 mode_t amode; 120 const int READ = 04; 121 const int WRITE = 02; 122 const int EXEC = 01; 123 124 KASSERT(aclp->acl_cnt >= 0, ("aclp->acl_cnt >= 0")); 125 KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, 126 ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 127 128 /* 129 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 130 * 131 * 3.16.6.3. Applying a Mode to an Existing ACL 132 */ 133 134 /* 135 * 1. For each ACE: 136 */ 137 for (i = 0; i < aclp->acl_cnt; i++) { 138 entry = &(aclp->acl_entry[i]); 139 140 /* 141 * 1.1. If the type is neither ALLOW or DENY - skip. 142 */ 143 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 144 entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 145 continue; 146 147 /* 148 * 1.2. If ACL_ENTRY_INHERIT_ONLY is set - skip. 149 */ 150 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) 151 continue; 152 153 /* 154 * 1.3. If ACL_ENTRY_FILE_INHERIT or ACL_ENTRY_DIRECTORY_INHERIT 155 * are set: 156 */ 157 if (entry->ae_flags & 158 (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT)) { 159 /* 160 * 1.3.1. A copy of the current ACE is made, and placed 161 * in the ACL immediately following the current 162 * ACE. 163 */ 164 copy = _acl_duplicate_entry(aclp, i); 165 166 /* 167 * 1.3.2. In the first ACE, the flag 168 * ACL_ENTRY_INHERIT_ONLY is set. 169 */ 170 entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 171 172 /* 173 * 1.3.3. In the second ACE, the following flags 174 * are cleared: 175 * ACL_ENTRY_FILE_INHERIT, 176 * ACL_ENTRY_DIRECTORY_INHERIT, 177 * ACL_ENTRY_NO_PROPAGATE_INHERIT. 178 */ 179 copy->ae_flags &= ~(ACL_ENTRY_FILE_INHERIT | 180 ACL_ENTRY_DIRECTORY_INHERIT | 181 ACL_ENTRY_NO_PROPAGATE_INHERIT); 182 183 /* 184 * The algorithm continues on with the second ACE. 185 */ 186 i++; 187 entry = copy; 188 } 189 190 /* 191 * 1.4. If it's owner@, group@ or everyone@ entry, clear 192 * ACL_READ_DATA, ACL_WRITE_DATA, ACL_APPEND_DATA 193 * and ACL_EXECUTE. Continue to the next entry. 194 */ 195 if (entry->ae_tag == ACL_USER_OBJ || 196 entry->ae_tag == ACL_GROUP_OBJ || 197 entry->ae_tag == ACL_EVERYONE) { 198 entry->ae_perm &= ~(ACL_READ_DATA | ACL_WRITE_DATA | 199 ACL_APPEND_DATA | ACL_EXECUTE); 200 continue; 201 } 202 203 /* 204 * 1.5. Otherwise, if the "who" field did not match one 205 * of OWNER@, GROUP@, EVERYONE@: 206 * 207 * 1.5.1. If the type is ALLOW, check the preceding ACE. 208 * If it does not meet all of the following criteria: 209 */ 210 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW) 211 continue; 212 213 meets = 0; 214 if (i > 0) { 215 meets = 1; 216 previous = &(aclp->acl_entry[i - 1]); 217 218 /* 219 * 1.5.1.1. The type field is DENY, 220 */ 221 if (previous->ae_entry_type != ACL_ENTRY_TYPE_DENY) 222 meets = 0; 223 224 /* 225 * 1.5.1.2. The "who" field is the same as the current 226 * ACE, 227 * 228 * 1.5.1.3. The flag bit ACE4_IDENTIFIER_GROUP 229 * is the same as it is in the current ACE, 230 * and no other flag bits are set, 231 */ 232 if (previous->ae_id != entry->ae_id || 233 previous->ae_tag != entry->ae_tag) 234 meets = 0; 235 236 if (previous->ae_flags) 237 meets = 0; 238 239 /* 240 * 1.5.1.4. The mask bits are a subset of the mask bits 241 * of the current ACE, and are also subset of 242 * the following: ACL_READ_DATA, 243 * ACL_WRITE_DATA, ACL_APPEND_DATA, ACL_EXECUTE 244 */ 245 if (previous->ae_perm & ~(entry->ae_perm)) 246 meets = 0; 247 248 if (previous->ae_perm & ~(ACL_READ_DATA | 249 ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE)) 250 meets = 0; 251 } 252 253 if (!meets) { 254 /* 255 * Then the ACE of type DENY, with a who equal 256 * to the current ACE, flag bits equal to 257 * (<current ACE flags> & <ACE_IDENTIFIER_GROUP>) 258 * and no mask bits, is prepended. 259 */ 260 previous = entry; 261 entry = _acl_duplicate_entry(aclp, i); 262 263 /* Adjust counter, as we've just added an entry. */ 264 i++; 265 266 previous->ae_tag = entry->ae_tag; 267 previous->ae_id = entry->ae_id; 268 previous->ae_flags = entry->ae_flags; 269 previous->ae_perm = 0; 270 previous->ae_entry_type = ACL_ENTRY_TYPE_DENY; 271 } 272 273 /* 274 * 1.5.2. The following modifications are made to the prepended 275 * ACE. The intent is to mask the following ACE 276 * to disallow ACL_READ_DATA, ACL_WRITE_DATA, 277 * ACL_APPEND_DATA, or ACL_EXECUTE, based upon the group 278 * permissions of the new mode. As a special case, 279 * if the ACE matches the current owner of the file, 280 * the owner bits are used, rather than the group bits. 281 * This is reflected in the algorithm below. 282 */ 283 amode = mode >> 3; 284 285 /* 286 * If ACE4_IDENTIFIER_GROUP is not set, and the "who" field 287 * in ACE matches the owner of the file, we shift amode three 288 * more bits, in order to have the owner permission bits 289 * placed in the three low order bits of amode. 290 */ 291 if (entry->ae_tag == ACL_USER && entry->ae_id == file_owner_id) 292 amode = amode >> 3; 293 294 if (entry->ae_perm & ACL_READ_DATA) { 295 if (amode & READ) 296 previous->ae_perm &= ~ACL_READ_DATA; 297 else 298 previous->ae_perm |= ACL_READ_DATA; 299 } 300 301 if (entry->ae_perm & ACL_WRITE_DATA) { 302 if (amode & WRITE) 303 previous->ae_perm &= ~ACL_WRITE_DATA; 304 else 305 previous->ae_perm |= ACL_WRITE_DATA; 306 } 307 308 if (entry->ae_perm & ACL_APPEND_DATA) { 309 if (amode & WRITE) 310 previous->ae_perm &= ~ACL_APPEND_DATA; 311 else 312 previous->ae_perm |= ACL_APPEND_DATA; 313 } 314 315 if (entry->ae_perm & ACL_EXECUTE) { 316 if (amode & EXEC) 317 previous->ae_perm &= ~ACL_EXECUTE; 318 else 319 previous->ae_perm |= ACL_EXECUTE; 320 } 321 322 /* 323 * 1.5.3. If ACE4_IDENTIFIER_GROUP is set in the flags 324 * of the ALLOW ace: 325 * 326 * XXX: This point is not there in the Falkner's draft. 327 */ 328 if (entry->ae_tag == ACL_GROUP && 329 entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) { 330 mode_t extramode, ownermode; 331 extramode = (mode >> 3) & 07; 332 ownermode = mode >> 6; 333 extramode &= ~ownermode; 334 335 if (extramode) { 336 if (extramode & READ) { 337 entry->ae_perm &= ~ACL_READ_DATA; 338 previous->ae_perm &= ~ACL_READ_DATA; 339 } 340 341 if (extramode & WRITE) { 342 entry->ae_perm &= 343 ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 344 previous->ae_perm &= 345 ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 346 } 347 348 if (extramode & EXEC) { 349 entry->ae_perm &= ~ACL_EXECUTE; 350 previous->ae_perm &= ~ACL_EXECUTE; 351 } 352 } 353 } 354 } 355 356 /* 357 * 2. If there at least six ACEs, the final six ACEs are examined. 358 * If they are not equal to what we want, append six ACEs. 359 */ 360 must_append = 0; 361 if (aclp->acl_cnt < 6) { 362 must_append = 1; 363 } else { 364 a6 = &(aclp->acl_entry[aclp->acl_cnt - 1]); 365 a5 = &(aclp->acl_entry[aclp->acl_cnt - 2]); 366 a4 = &(aclp->acl_entry[aclp->acl_cnt - 3]); 367 a3 = &(aclp->acl_entry[aclp->acl_cnt - 4]); 368 a2 = &(aclp->acl_entry[aclp->acl_cnt - 5]); 369 a1 = &(aclp->acl_entry[aclp->acl_cnt - 6]); 370 371 if (!_acl_entry_matches(a1, ACL_USER_OBJ, 0, 372 ACL_ENTRY_TYPE_DENY)) 373 must_append = 1; 374 if (!_acl_entry_matches(a2, ACL_USER_OBJ, ACL_WRITE_ACL | 375 ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 376 ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW)) 377 must_append = 1; 378 if (!_acl_entry_matches(a3, ACL_GROUP_OBJ, 0, 379 ACL_ENTRY_TYPE_DENY)) 380 must_append = 1; 381 if (!_acl_entry_matches(a4, ACL_GROUP_OBJ, 0, 382 ACL_ENTRY_TYPE_ALLOW)) 383 must_append = 1; 384 if (!_acl_entry_matches(a5, ACL_EVERYONE, ACL_WRITE_ACL | 385 ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 386 ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY)) 387 must_append = 1; 388 if (!_acl_entry_matches(a6, ACL_EVERYONE, ACL_READ_ACL | 389 ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | 390 ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW)) 391 must_append = 1; 392 } 393 394 if (must_append) { 395 KASSERT(aclp->acl_cnt + 6 <= ACL_MAX_ENTRIES, 396 ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 397 398 a1 = _acl_append(aclp, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY); 399 a2 = _acl_append(aclp, ACL_USER_OBJ, ACL_WRITE_ACL | 400 ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 401 ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW); 402 a3 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY); 403 a4 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW); 404 a5 = _acl_append(aclp, ACL_EVERYONE, ACL_WRITE_ACL | 405 ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 406 ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY); 407 a6 = _acl_append(aclp, ACL_EVERYONE, ACL_READ_ACL | 408 ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | 409 ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW); 410 411 KASSERT(a1 != NULL && a2 != NULL && a3 != NULL && a4 != NULL && 412 a5 != NULL && a6 != NULL, ("couldn't append to ACL.")); 413 } 414 415 /* 416 * 3. The final six ACEs are adjusted according to the incoming mode. 417 */ 418 if (mode & S_IRUSR) 419 a2->ae_perm |= ACL_READ_DATA; 420 else 421 a1->ae_perm |= ACL_READ_DATA; 422 if (mode & S_IWUSR) 423 a2->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 424 else 425 a1->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 426 if (mode & S_IXUSR) 427 a2->ae_perm |= ACL_EXECUTE; 428 else 429 a1->ae_perm |= ACL_EXECUTE; 430 431 if (mode & S_IRGRP) 432 a4->ae_perm |= ACL_READ_DATA; 433 else 434 a3->ae_perm |= ACL_READ_DATA; 435 if (mode & S_IWGRP) 436 a4->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 437 else 438 a3->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 439 if (mode & S_IXGRP) 440 a4->ae_perm |= ACL_EXECUTE; 441 else 442 a3->ae_perm |= ACL_EXECUTE; 443 444 if (mode & S_IROTH) 445 a6->ae_perm |= ACL_READ_DATA; 446 else 447 a5->ae_perm |= ACL_READ_DATA; 448 if (mode & S_IWOTH) 449 a6->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 450 else 451 a5->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 452 if (mode & S_IXOTH) 453 a6->ae_perm |= ACL_EXECUTE; 454 else 455 a5->ae_perm |= ACL_EXECUTE; 456 } 457 458 void 459 acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp) 460 { 461 int i; 462 mode_t old_mode = *_mode, mode = 0, seen = 0; 463 const struct acl_entry *entry; 464 465 KASSERT(aclp->acl_cnt > 0, ("aclp->acl_cnt > 0")); 466 KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, 467 ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 468 469 /* 470 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 471 * 472 * 3.16.6.1. Recomputing mode upon SETATTR of ACL 473 */ 474 475 for (i = 0; i < aclp->acl_cnt; i++) { 476 entry = &(aclp->acl_entry[i]); 477 478 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 479 entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 480 continue; 481 482 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) 483 continue; 484 485 if (entry->ae_tag == ACL_USER_OBJ) { 486 if ((entry->ae_perm & ACL_READ_DATA) && 487 ((seen & S_IRUSR) == 0)) { 488 seen |= S_IRUSR; 489 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 490 mode |= S_IRUSR; 491 } 492 if ((entry->ae_perm & ACL_WRITE_DATA) && 493 ((seen & S_IWUSR) == 0)) { 494 seen |= S_IWUSR; 495 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 496 mode |= S_IWUSR; 497 } 498 if ((entry->ae_perm & ACL_EXECUTE) && 499 ((seen & S_IXUSR) == 0)) { 500 seen |= S_IXUSR; 501 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 502 mode |= S_IXUSR; 503 } 504 } else if (entry->ae_tag == ACL_GROUP_OBJ) { 505 if ((entry->ae_perm & ACL_READ_DATA) && 506 ((seen & S_IRGRP) == 0)) { 507 seen |= S_IRGRP; 508 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 509 mode |= S_IRGRP; 510 } 511 if ((entry->ae_perm & ACL_WRITE_DATA) && 512 ((seen & S_IWGRP) == 0)) { 513 seen |= S_IWGRP; 514 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 515 mode |= S_IWGRP; 516 } 517 if ((entry->ae_perm & ACL_EXECUTE) && 518 ((seen & S_IXGRP) == 0)) { 519 seen |= S_IXGRP; 520 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 521 mode |= S_IXGRP; 522 } 523 } else if (entry->ae_tag == ACL_EVERYONE) { 524 if (entry->ae_perm & ACL_READ_DATA) { 525 if ((seen & S_IRUSR) == 0) { 526 seen |= S_IRUSR; 527 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 528 mode |= S_IRUSR; 529 } 530 if ((seen & S_IRGRP) == 0) { 531 seen |= S_IRGRP; 532 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 533 mode |= S_IRGRP; 534 } 535 if ((seen & S_IROTH) == 0) { 536 seen |= S_IROTH; 537 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 538 mode |= S_IROTH; 539 } 540 } 541 if (entry->ae_perm & ACL_WRITE_DATA) { 542 if ((seen & S_IWUSR) == 0) { 543 seen |= S_IWUSR; 544 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 545 mode |= S_IWUSR; 546 } 547 if ((seen & S_IWGRP) == 0) { 548 seen |= S_IWGRP; 549 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 550 mode |= S_IWGRP; 551 } 552 if ((seen & S_IWOTH) == 0) { 553 seen |= S_IWOTH; 554 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 555 mode |= S_IWOTH; 556 } 557 } 558 if (entry->ae_perm & ACL_EXECUTE) { 559 if ((seen & S_IXUSR) == 0) { 560 seen |= S_IXUSR; 561 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 562 mode |= S_IXUSR; 563 } 564 if ((seen & S_IXGRP) == 0) { 565 seen |= S_IXGRP; 566 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 567 mode |= S_IXGRP; 568 } 569 if ((seen & S_IXOTH) == 0) { 570 seen |= S_IXOTH; 571 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 572 mode |= S_IXOTH; 573 } 574 } 575 } 576 } 577 578 *_mode = mode | (old_mode & ACL_PRESERVE_MASK); 579 } 580