1 /* copy-acl.c - copy access control list from one file to another file 2 3 Copyright (C) 2002-2003, 2005-2008 Free Software Foundation, Inc. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 Written by Paul Eggert, Andreas Grnbacher, and Bruno Haible. */ 19 20 #include <config.h> 21 22 #include "acl.h" 23 24 #include "acl-internal.h" 25 26 #include "gettext.h" 27 #define _(msgid) gettext (msgid) 28 29 30 /* Copy access control lists from one file to another. If SOURCE_DESC is 31 a valid file descriptor, use file descriptor operations, else use 32 filename based operations on SRC_NAME. Likewise for DEST_DESC and 33 DST_NAME. 34 If access control lists are not available, fchmod the target file to 35 MODE. Also sets the non-permission bits of the destination file 36 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. 37 Return 0 if successful. 38 Return -2 and set errno for an error relating to the source file. 39 Return -1 and set errno for an error relating to the destination file. */ 40 41 static int 42 qcopy_acl (const char *src_name, int source_desc, const char *dst_name, 43 int dest_desc, mode_t mode) 44 { 45 #if USE_ACL && HAVE_ACL_GET_FILE 46 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ 47 /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ 48 # if MODE_INSIDE_ACL 49 /* Linux, FreeBSD, IRIX, Tru64 */ 50 51 acl_t acl; 52 int ret; 53 54 if (HAVE_ACL_GET_FD && source_desc != -1) 55 acl = acl_get_fd (source_desc); 56 else 57 acl = acl_get_file (src_name, ACL_TYPE_ACCESS); 58 if (acl == NULL) 59 { 60 if (ACL_NOT_WELL_SUPPORTED (errno)) 61 return qset_acl (dst_name, dest_desc, mode); 62 else 63 return -2; 64 } 65 66 if (HAVE_ACL_SET_FD && dest_desc != -1) 67 ret = acl_set_fd (dest_desc, acl); 68 else 69 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); 70 if (ret != 0) 71 { 72 int saved_errno = errno; 73 74 if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl)) 75 { 76 acl_free (acl); 77 return chmod_or_fchmod (dst_name, dest_desc, mode); 78 } 79 else 80 { 81 acl_free (acl); 82 chmod_or_fchmod (dst_name, dest_desc, mode); 83 errno = saved_errno; 84 return -1; 85 } 86 } 87 else 88 acl_free (acl); 89 90 if (mode & (S_ISUID | S_ISGID | S_ISVTX)) 91 { 92 /* We did not call chmod so far, and either the mode and the ACL are 93 separate or special bits are to be set which don't fit into ACLs. */ 94 95 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) 96 return -1; 97 } 98 99 if (S_ISDIR (mode)) 100 { 101 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); 102 if (acl == NULL) 103 return -2; 104 105 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) 106 { 107 int saved_errno = errno; 108 109 acl_free (acl); 110 errno = saved_errno; 111 return -1; 112 } 113 else 114 acl_free (acl); 115 } 116 return 0; 117 118 # else /* !MODE_INSIDE_ACL */ 119 /* MacOS X */ 120 121 # if !HAVE_ACL_TYPE_EXTENDED 122 # error Must have ACL_TYPE_EXTENDED 123 # endif 124 125 /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) 126 and acl_get_file (name, ACL_TYPE_DEFAULT) 127 always return NULL / EINVAL. You have to use 128 acl_get_file (name, ACL_TYPE_EXTENDED) 129 or acl_get_fd (open (name, ...)) 130 to retrieve an ACL. 131 On the other hand, 132 acl_set_file (name, ACL_TYPE_ACCESS, acl) 133 and acl_set_file (name, ACL_TYPE_DEFAULT, acl) 134 have the same effect as 135 acl_set_file (name, ACL_TYPE_EXTENDED, acl): 136 Each of these calls sets the file's ACL. */ 137 138 acl_t acl; 139 int ret; 140 141 if (HAVE_ACL_GET_FD && source_desc != -1) 142 acl = acl_get_fd (source_desc); 143 else 144 acl = acl_get_file (src_name, ACL_TYPE_EXTENDED); 145 if (acl == NULL) 146 { 147 if (ACL_NOT_WELL_SUPPORTED (errno)) 148 return qset_acl (dst_name, dest_desc, mode); 149 else 150 return -2; 151 } 152 153 if (HAVE_ACL_SET_FD && dest_desc != -1) 154 ret = acl_set_fd (dest_desc, acl); 155 else 156 ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl); 157 if (ret != 0) 158 { 159 int saved_errno = errno; 160 161 if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl)) 162 { 163 acl_free (acl); 164 return chmod_or_fchmod (dst_name, dest_desc, mode); 165 } 166 else 167 { 168 acl_free (acl); 169 chmod_or_fchmod (dst_name, dest_desc, mode); 170 errno = saved_errno; 171 return -1; 172 } 173 } 174 else 175 acl_free (acl); 176 177 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ 178 return chmod_or_fchmod (dst_name, dest_desc, mode); 179 180 # endif 181 182 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ 183 184 # if defined ACL_NO_TRIVIAL 185 /* Solaris 10 (newer version), which has additional API declared in 186 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, 187 acl_fromtext, ...). */ 188 189 int ret; 190 acl_t *aclp = NULL; 191 ret = (source_desc < 0 192 ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp) 193 : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp)); 194 if (ret != 0 && errno != ENOSYS) 195 return -2; 196 197 ret = qset_acl (dst_name, dest_desc, mode); 198 if (ret != 0) 199 return -1; 200 201 if (aclp) 202 { 203 ret = (dest_desc < 0 204 ? acl_set (dst_name, aclp) 205 : facl_set (dest_desc, aclp)); 206 if (ret != 0) 207 { 208 int saved_errno = errno; 209 210 acl_free (aclp); 211 errno = saved_errno; 212 return -1; 213 } 214 acl_free (aclp); 215 } 216 217 return 0; 218 219 # else /* Solaris, Cygwin, general case */ 220 221 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions 222 of Unixware. The acl() call returns the access and default ACL both 223 at once. */ 224 # ifdef ACE_GETACL 225 int ace_count; 226 ace_t *ace_entries; 227 # endif 228 int count; 229 aclent_t *entries; 230 int did_chmod; 231 int saved_errno; 232 int ret; 233 234 # ifdef ACE_GETACL 235 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 236 file systems (whereas the other ones are used in UFS file systems). 237 There is an API 238 pathconf (name, _PC_ACL_ENABLED) 239 fpathconf (desc, _PC_ACL_ENABLED) 240 that allows to determine which of the two kinds of ACLs is supported 241 for the given file. But some file systems may implement this call 242 incorrectly, so better not use it. 243 When fetching the source ACL, we simply fetch both ACL types. 244 When setting the destination ACL, we try either ACL types, assuming 245 that the kernel will translate the ACL from one form to the other. 246 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view> 247 the description of ENOTSUP.) */ 248 for (;;) 249 { 250 ace_count = (source_desc != -1 251 ? facl (source_desc, ACE_GETACLCNT, 0, NULL) 252 : acl (src_name, ACE_GETACLCNT, 0, NULL)); 253 254 if (ace_count < 0) 255 { 256 if (errno == ENOSYS || errno == EINVAL) 257 { 258 ace_count = 0; 259 ace_entries = NULL; 260 break; 261 } 262 else 263 return -2; 264 } 265 266 if (ace_count == 0) 267 { 268 ace_entries = NULL; 269 break; 270 } 271 272 ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t)); 273 if (ace_entries == NULL) 274 { 275 errno = ENOMEM; 276 return -2; 277 } 278 279 if ((source_desc != -1 280 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries) 281 : acl (src_name, ACE_GETACL, ace_count, ace_entries)) 282 == ace_count) 283 break; 284 /* Huh? The number of ACL entries changed since the last call. 285 Repeat. */ 286 } 287 # endif 288 289 for (;;) 290 { 291 count = (source_desc != -1 292 ? facl (source_desc, GETACLCNT, 0, NULL) 293 : acl (src_name, GETACLCNT, 0, NULL)); 294 295 if (count < 0) 296 { 297 if (errno == ENOSYS || errno == ENOTSUP) 298 { 299 count = 0; 300 entries = NULL; 301 break; 302 } 303 else 304 return -2; 305 } 306 307 if (count == 0) 308 { 309 entries = NULL; 310 break; 311 } 312 313 entries = (aclent_t *) malloc (count * sizeof (aclent_t)); 314 if (entries == NULL) 315 { 316 errno = ENOMEM; 317 return -2; 318 } 319 320 if ((source_desc != -1 321 ? facl (source_desc, GETACL, count, entries) 322 : acl (src_name, GETACL, count, entries)) 323 == count) 324 break; 325 /* Huh? The number of ACL entries changed since the last call. 326 Repeat. */ 327 } 328 329 /* Is there an ACL of either kind? */ 330 # ifdef ACE_GETACL 331 if (ace_count == 0) 332 # endif 333 if (count == 0) 334 return qset_acl (dst_name, dest_desc, mode); 335 336 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ 337 saved_errno = 0; /* the first non-ignorable error code */ 338 339 if (!MODE_INSIDE_ACL) 340 { 341 /* On Cygwin, it is necessary to call chmod before acl, because 342 chmod can change the contents of the ACL (in ways that don't 343 change the allowed accesses, but still visible). */ 344 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) 345 saved_errno = errno; 346 did_chmod = 1; 347 } 348 349 /* If both ace_entries and entries are available, try SETACL before 350 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL 351 can. */ 352 353 if (count > 0) 354 { 355 ret = (dest_desc != -1 356 ? facl (dest_desc, SETACL, count, entries) 357 : acl (dst_name, SETACL, count, entries)); 358 if (ret < 0 && saved_errno == 0) 359 { 360 saved_errno = errno; 361 if (errno == ENOSYS && !acl_nontrivial (count, entries)) 362 saved_errno = 0; 363 } 364 else 365 did_chmod = 1; 366 } 367 free (entries); 368 369 # ifdef ACE_GETACL 370 if (ace_count > 0) 371 { 372 ret = (dest_desc != -1 373 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries) 374 : acl (dst_name, ACE_SETACL, ace_count, ace_entries)); 375 if (ret < 0 && saved_errno == 0) 376 { 377 saved_errno = errno; 378 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP) 379 && !acl_ace_nontrivial (ace_count, ace_entries)) 380 saved_errno = 0; 381 } 382 } 383 free (ace_entries); 384 # endif 385 386 if (MODE_INSIDE_ACL 387 && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) 388 { 389 /* We did not call chmod so far, and either the mode and the ACL are 390 separate or special bits are to be set which don't fit into ACLs. */ 391 392 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) 393 { 394 if (saved_errno == 0) 395 saved_errno = errno; 396 } 397 } 398 399 if (saved_errno) 400 { 401 errno = saved_errno; 402 return -1; 403 } 404 return 0; 405 406 # endif 407 408 #elif USE_ACL && HAVE_GETACL /* HP-UX */ 409 410 int count; 411 struct acl_entry entries[NACLENTRIES]; 412 int ret; 413 414 for (;;) 415 { 416 count = (source_desc != -1 417 ? fgetacl (source_desc, 0, NULL) 418 : getacl (src_name, 0, NULL)); 419 420 if (count < 0) 421 { 422 if (errno == ENOSYS || errno == EOPNOTSUPP) 423 { 424 count = 0; 425 break; 426 } 427 else 428 return -2; 429 } 430 431 if (count == 0) 432 break; 433 434 if (count > NACLENTRIES) 435 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ 436 abort (); 437 438 if ((source_desc != -1 439 ? fgetacl (source_desc, count, entries) 440 : getacl (src_name, count, entries)) 441 == count) 442 break; 443 /* Huh? The number of ACL entries changed since the last call. 444 Repeat. */ 445 } 446 447 if (count == 0) 448 return qset_acl (dst_name, dest_desc, mode); 449 450 ret = (dest_desc != -1 451 ? fsetacl (dest_desc, count, entries) 452 : setacl (dst_name, count, entries)); 453 if (ret < 0) 454 { 455 int saved_errno = errno; 456 457 if (errno == ENOSYS || errno == EOPNOTSUPP) 458 { 459 struct stat source_statbuf; 460 461 if ((source_desc != -1 462 ? fstat (source_desc, &source_statbuf) 463 : stat (src_name, &source_statbuf)) == 0) 464 { 465 if (!acl_nontrivial (count, entries, &source_statbuf)) 466 return chmod_or_fchmod (dst_name, dest_desc, mode); 467 } 468 else 469 saved_errno = errno; 470 } 471 472 chmod_or_fchmod (dst_name, dest_desc, mode); 473 errno = saved_errno; 474 return -1; 475 } 476 477 if (mode & (S_ISUID | S_ISGID | S_ISVTX)) 478 { 479 /* We did not call chmod so far, and either the mode and the ACL are 480 separate or special bits are to be set which don't fit into ACLs. */ 481 482 return chmod_or_fchmod (dst_name, dest_desc, mode); 483 } 484 return 0; 485 486 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ 487 488 /* TODO */ 489 490 #elif USE_ACL && HAVE_STATACL /* older AIX */ 491 492 union { struct acl a; char room[4096]; } u; 493 int ret; 494 495 if ((source_desc != -1 496 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u)) 497 : statacl (src_name, STX_NORMAL, &u.a, sizeof (u))) 498 < 0) 499 return -2; 500 501 ret = (dest_desc != -1 502 ? fchacl (dest_desc, &u.a, u.a.acl_len) 503 : chacl (dst_name, &u.a, u.a.acl_len)); 504 if (ret < 0) 505 { 506 int saved_errno = errno; 507 508 chmod_or_fchmod (dst_name, dest_desc, mode); 509 errno = saved_errno; 510 return -1; 511 } 512 513 /* No need to call chmod_or_fchmod at this point, since the mode bits 514 S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ 515 516 return 0; 517 518 #else 519 520 return qset_acl (dst_name, dest_desc, mode); 521 522 #endif 523 } 524 525 526 /* Copy access control lists from one file to another. If SOURCE_DESC is 527 a valid file descriptor, use file descriptor operations, else use 528 filename based operations on SRC_NAME. Likewise for DEST_DESC and 529 DST_NAME. 530 If access control lists are not available, fchmod the target file to 531 MODE. Also sets the non-permission bits of the destination file 532 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. 533 Return 0 if successful, otherwise output a diagnostic and return -1. */ 534 535 int 536 copy_acl (const char *src_name, int source_desc, const char *dst_name, 537 int dest_desc, mode_t mode) 538 { 539 int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode); 540 switch (ret) 541 { 542 case -2: 543 error (0, errno, "%s", quote (src_name)); 544 return -1; 545 546 case -1: 547 error (0, errno, _("preserving permissions for %s"), quote (dst_name)); 548 return -1; 549 550 default: 551 return 0; 552 } 553 } 554