]> git.saurik.com Git - apple/copyfile.git/blob - copyfile.c
aa68b5c27f7d1e755526e5501d453fc3878aea1c
[apple/copyfile.git] / copyfile.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <err.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/acl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/errno.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/xattr.h>
39 #include <sys/syscall.h>
40 #include <sys/param.h>
41 #include <sys/mount.h>
42 #include <sys/acl.h>
43 #include <libkern/OSByteOrder.h>
44 #include <membership.h>
45 #include <fts.h>
46 #include <libgen.h>
47
48 #include <TargetConditionals.h>
49 #if !TARGET_OS_EMBEDDED
50 #include <quarantine.h>
51
52 #define XATTR_QUARANTINE_NAME qtn_xattr_name
53 #else /* TARGET_OS_EMBEDDED */
54 #define qtn_file_t void *
55 #define QTN_SERIALIZED_DATA_MAX 0
56 static void * qtn_file_alloc(void) { return NULL; }
57 static int qtn_file_init_with_fd(void *x, int y) { return -1; }
58 static void qtn_file_free(void *x) { return; }
59 static int qtn_file_apply_to_fd(void *x, int y) { return -1; }
60 static char *qtn_error(int x) { return NULL; }
61 static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; }
62 static void *qtn_file_clone(void *x) { return NULL; }
63 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
64 #endif /* TARGET_OS_EMBEDDED */
65
66 #include "copyfile.h"
67
68 enum cfInternalFlags {
69 cfDelayAce = 1,
70 };
71
72 /*
73 * The state structure keeps track of
74 * the source filename, the destination filename, their
75 * associated file-descriptors, the stat infomration for the
76 * source file, the security information for the source file,
77 * the flags passed in for the copy, a pointer to place statistics
78 * (not currently implemented), debug flags, and a pointer to callbacks
79 * (not currently implemented).
80 */
81 struct _copyfile_state
82 {
83 char *src;
84 char *dst;
85 int src_fd;
86 int dst_fd;
87 struct stat sb;
88 filesec_t fsec;
89 copyfile_flags_t flags;
90 unsigned int internal_flags;
91 void *stats;
92 uint32_t debug;
93 copyfile_callback_t statuscb;
94 void *ctx;
95 qtn_file_t qinfo; /* Quarantine information -- probably NULL */
96 filesec_t original_fsec;
97 filesec_t permissive_fsec;
98 off_t totalCopied;
99 int err;
100 };
101
102 struct acl_entry {
103 u_int32_t ae_magic;
104 #define _ACL_ENTRY_MAGIC 0xac1ac101
105 u_int32_t ae_tag;
106 guid_t ae_applicable;
107 u_int32_t ae_flags;
108 u_int32_t ae_perms;
109 };
110
111 #define PACE(ace) do { \
112 struct acl_entry *__t = (struct acl_entry*)(ace); \
113 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
114 } while (0)
115
116 #define PACL(ace) \
117 do { \
118 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
119 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
120 } while (0)
121
122 static int
123 acl_compare_permset_np(acl_permset_t p1, acl_permset_t p2)
124 {
125 struct pm { u_int32_t ap_perms; } *ps1, *ps2;
126 ps1 = (struct pm*) p1;
127 ps2 = (struct pm*) p2;
128
129 return ((ps1->ap_perms == ps2->ap_perms) ? 1 : 0);
130 }
131
132 /*
133 * Internally, the process is broken into a series of
134 * private functions.
135 */
136 static int copyfile_open (copyfile_state_t);
137 static int copyfile_close (copyfile_state_t);
138 static int copyfile_data (copyfile_state_t);
139 static int copyfile_stat (copyfile_state_t);
140 static int copyfile_security (copyfile_state_t);
141 static int copyfile_xattr (copyfile_state_t);
142 static int copyfile_pack (copyfile_state_t);
143 static int copyfile_unpack (copyfile_state_t);
144
145 static copyfile_flags_t copyfile_check (copyfile_state_t);
146 static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *);
147 static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags);
148 static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags);
149 static int copyfile_unset_posix_fsec(filesec_t);
150 static int copyfile_quarantine(copyfile_state_t);
151
152 #define COPYFILE_DEBUG (1<<31)
153 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
154
155 #ifndef _COPYFILE_TEST
156 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
157 # define copyfile_debug(d, str, ...) \
158 do { \
159 if (s && (d <= s->debug)) {\
160 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
161 } \
162 } while (0)
163 #else
164 #define copyfile_warn(str, ...) \
165 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
166 # define copyfile_debug(d, str, ...) \
167 do { \
168 if (s && (d <= s->debug)) {\
169 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
170 } \
171 } while(0)
172 #endif
173
174 static int copyfile_quarantine(copyfile_state_t s)
175 {
176 int rv = 0;
177 if (s->qinfo == NULL)
178 {
179 int error;
180 s->qinfo = qtn_file_alloc();
181 if (s->qinfo == NULL)
182 {
183 rv = -1;
184 goto done;
185 }
186 if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0)
187 {
188 qtn_file_free(s->qinfo);
189 s->qinfo = NULL;
190 rv = -1;
191 goto done;
192 }
193 }
194 done:
195 return rv;
196 }
197
198 static int
199 add_uberace(acl_t *acl)
200 {
201 acl_entry_t entry;
202 acl_permset_t permset;
203 uuid_t qual;
204
205 if (mbr_uid_to_uuid(getuid(), qual) != 0)
206 goto error_exit;
207
208 /*
209 * First, we create an entry, and give it the special name
210 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
211 * After that, we clear out all the permissions in it, and
212 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
213 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
214 * the functionality, and put this into the ACL.
215 */
216 if (acl_create_entry_np(acl, &entry, ACL_FIRST_ENTRY) == -1)
217 goto error_exit;
218 if (acl_get_permset(entry, &permset) == -1)
219 goto error_exit;
220 if (acl_clear_perms(permset) == -1)
221 goto error_exit;
222 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
223 goto error_exit;
224 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
225 goto error_exit;
226 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
227 goto error_exit;
228 if (acl_add_perm(permset, ACL_APPEND_DATA) == -1)
229 goto error_exit;
230 if (acl_add_perm(permset, ACL_WRITE_SECURITY) == -1)
231 goto error_exit;
232 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
233 goto error_exit;
234
235 if(acl_set_permset(entry, permset) == -1)
236 goto error_exit;
237 if(acl_set_qualifier(entry, qual) == -1)
238 goto error_exit;
239
240 return 0;
241 error_exit:
242 return -1;
243 }
244
245 static int
246 is_uberace(acl_entry_t ace)
247 {
248 int retval = 0;
249 acl_permset_t perms, tperms;
250 acl_t tacl;
251 acl_entry_t tentry;
252 acl_tag_t tag;
253 guid_t *qual;
254 uuid_t myuuid;
255
256 // Who am I, and who is the ACE for?
257 mbr_uid_to_uuid(geteuid(), myuuid);
258 qual = (guid_t*)acl_get_qualifier(ace);
259
260 // Need to create a temporary acl, so I can get the uberace template.
261 tacl = acl_init(1);
262 if (tacl == NULL) {
263 goto done;
264 }
265 add_uberace(&tacl);
266 if (acl_get_entry(tacl, ACL_FIRST_ENTRY, &tentry) != 0) {
267 goto done;
268 }
269 acl_get_permset(tentry, &tperms);
270
271 // Now I need to get
272 acl_get_tag_type(ace, &tag);
273 acl_get_permset(ace, &perms);
274
275 if (tag == ACL_EXTENDED_ALLOW &&
276 (memcmp(qual, myuuid, sizeof(myuuid)) == 0) &&
277 acl_compare_permset_np(tperms, perms))
278 retval = 1;
279
280 done:
281
282 if (tacl)
283 acl_free(tacl);
284
285 return retval;
286 }
287
288 static void
289 remove_uberace(int fd, struct stat *sbuf)
290 {
291 filesec_t fsec = NULL;
292 acl_t acl = NULL;
293 acl_entry_t entry;
294 struct stat sb;
295
296 fsec = filesec_init();
297 if (fsec == NULL) {
298 goto noacl;
299 }
300
301 if (fstatx_np(fd, &sb, fsec) != 0) {
302 if (errno == ENOTSUP)
303 goto noacl;
304 goto done;
305 }
306
307 if (filesec_get_property(fsec, FILESEC_ACL, &acl) != 0) {
308 goto done;
309 }
310
311 if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 0) {
312 if (is_uberace(entry))
313 {
314 mode_t m = sbuf->st_mode & ~S_IFMT;
315
316 if (acl_delete_entry(acl, entry) != 0 ||
317 filesec_set_property(fsec, FILESEC_ACL, &acl) != 0 ||
318 filesec_set_property(fsec, FILESEC_MODE, &m) != 0 ||
319 fchmodx_np(fd, fsec) != 0)
320 goto noacl;
321 }
322 }
323
324 done:
325 if (acl)
326 acl_free(acl);
327 if (fsec)
328 filesec_free(fsec);
329 return;
330
331 noacl:
332 fchmod(fd, sbuf->st_mode & ~S_IFMT);
333 goto done;
334 }
335
336 static void
337 reset_security(copyfile_state_t s)
338 {
339 /* If we haven't reset the file security information
340 * (COPYFILE_SECURITY is not set in flags)
341 * restore back the permissions the file had originally
342 *
343 * One of the reasons this seems so complicated is that
344 * it is partially at odds with copyfile_security().
345 *
346 * Simplisticly, we are simply trying to make sure we
347 * only copy what was requested, and that we don't stomp
348 * on what wasn't requested.
349 */
350
351 #ifdef COPYFILE_RECURSIVE
352 if (s->dst_fd > -1) {
353 struct stat sbuf;
354
355 if (s->src_fd > -1 && (s->flags & COPYFILE_STAT))
356 fstat(s->src_fd, &sbuf);
357 else
358 fstat(s->dst_fd, &sbuf);
359
360 if (!(s->internal_flags & cfDelayAce))
361 remove_uberace(s->dst_fd, &sbuf);
362 }
363 #else
364 if (s->permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) {
365 if (s->flags & COPYFILE_ACL) {
366 /* Just need to reset the BSD information -- mode, owner, group */
367 (void)fchown(s->dst_fd, s->dst_sb.st_uid, s->dst_sb.st_gid);
368 (void)fchmod(s->dst_fd, s->dst_sb.st_mode);
369 } else {
370 /*
371 * flags is either COPYFILE_STAT, or neither; if it's
372 * neither, then we restore both ACL and POSIX permissions;
373 * if it's STAT, however, then we only want to restore the
374 * ACL (which may be empty). We do that by removing the
375 * POSIX information from the filesec object.
376 */
377 if (s->flags & COPYFILE_STAT) {
378 copyfile_unset_posix_fsec(s->original_fsec);
379 }
380 if (fchmodx_np(s->dst_fd, s->original_fsec) < 0 && errno != ENOTSUP)
381 copyfile_warn("restoring security information");
382 }
383 }
384
385 if (s->permissive_fsec) {
386 filesec_free(s->permissive_fsec);
387 s->permissive_fsec = NULL;
388 }
389
390 if (s->original_fsec) {
391 filesec_free(s->original_fsec);
392 s->original_fsec = NULL;
393 }
394 #endif
395
396 return;
397 }
398
399 /*
400 * copytree -- recursively copy a hierarchy.
401 *
402 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
403 * Care is taken to keep the ACLs set up correctly, in addition to the
404 * normal copying that is done. (When copying a hierarchy, we can't
405 * get rid of the "allow-all-writes" ACE on a directory until we're done
406 * copying the *contents* of the directory.)
407 *
408 * The other big difference from copyfile (for the moment) is that copytree()
409 * will use a call-back function to pass along information about what is
410 * about to be copied, and whether or not it succeeded.
411 *
412 * copytree() is called from copyfile() -- but copytree() itself then calls
413 * copyfile() to copy each individual object.
414 *
415 * XXX - no effort is made to handle overlapping hierarchies at the moment.
416 *
417 */
418
419 static int
420 copytree(copyfile_state_t s)
421 {
422 char *slash;
423 int retval = 0;
424 int (*sfunc)(const char *, struct stat *);
425 copyfile_callback_t status = NULL;
426 char srcisdir = 0, dstisdir = 0, dstexists = 0;
427 struct stat sbuf;
428 char *src, *dst;
429 const char *dstpathsep = "";
430 #ifdef NOTYET
431 char srcpath[PATH_MAX * 2 + 1], dstpath[PATH_MAX * 2 + 1];
432 #endif
433 char *srcroot;
434 FTS *fts = NULL;
435 FTSENT *ftsent;
436 ssize_t offset = 0;
437 const char *paths[2] = { 0 };
438 unsigned int flags = 0;
439 int fts_flags = FTS_NOCHDIR;
440
441 if (s == NULL) {
442 errno = EINVAL;
443 retval = -1;
444 goto done;
445 }
446 if (s->flags & (COPYFILE_MOVE | COPYFILE_UNLINK | COPYFILE_CHECK | COPYFILE_PACK | COPYFILE_UNPACK)) {
447 errno = EINVAL;
448 retval = -1;
449 goto done;
450 }
451
452 flags = s->flags & (COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_VERBOSE);
453
454 paths[0] = src = s->src;
455 dst = s->dst;
456
457 if (src == NULL || dst == NULL) {
458 errno = EINVAL;
459 retval = -1;
460 goto done;
461 }
462
463 sfunc = (flags & COPYFILE_NOFOLLOW_SRC) ? lstat : stat;
464 if ((sfunc)(src, &sbuf) == -1) {
465 retval = -1;
466 goto done;
467 }
468 if (sbuf.st_mode & S_IFDIR) {
469 srcisdir = 1;
470 }
471
472 sfunc = (flags & COPYFILE_NOFOLLOW_DST) ? lstat : stat;
473 if ((sfunc)(dst, &sbuf) == -1) {
474 if (errno != ENOENT) {
475 retval = -1;
476 goto done;
477 }
478 } else {
479 dstexists = 1;
480 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
481 dstisdir = 1;
482 }
483 }
484
485 #ifdef NOTYET
486 // This doesn't handle filesystem crossing and case sensitivity
487 // So there's got to be a better way
488
489 if (realpath(src, srcpath) == NULL) {
490 retval = -1;
491 goto done;
492 }
493
494 if (realpath(dst, dstpath) == NULL &&
495 (errno == ENOENT && realpath(dirname(dst), dstpath) == NULL)) {
496 retval = -1;
497 goto done;
498 }
499 if (strstr(srcpath, dstpath) != NULL) {
500 errno = EINVAL;
501 retval = -1;
502 goto done;
503 }
504 #endif
505 srcroot = basename((char*)src);
506 if (srcroot == NULL) {
507 retval = -1;
508 goto done;
509 }
510
511 /*
512 * To work on as well:
513 * We have a few cases when copying a hierarchy:
514 * 1) src is a non-directory, dst is a directory;
515 * 2) src is a non-directory, dst is a non-directory;
516 * 3) src is a non-directory, dst does not exist;
517 * 4) src is a directory, dst is a directory;
518 * 5) src is a directory, dst is a non-directory;
519 * 6) src is a directory, dst does not exist
520 *
521 * (1) copies src to dst/basename(src).
522 * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst.
523 * (3) and (6) copy src to the name dst.
524 * (4) copies the contents of src to the contents of dst.
525 * (5) is an error.
526 */
527
528 if (dstisdir) {
529 // copy /path/to/src to /path/to/dst/src
530 // Append "/" and (fts_path - strlen(basename(src))) to dst?
531 dstpathsep = "/";
532 slash = strrchr(src, '/');
533 if (slash == NULL)
534 offset = 0;
535 else
536 offset = slash - src + 1;
537 } else {
538 // copy /path/to/src to /path/to/dst
539 // append (fts_path + strlen(src)) to dst?
540 dstpathsep = "";
541 offset = strlen(src);
542 }
543
544 if (s->flags | COPYFILE_NOFOLLOW_SRC)
545 fts_flags |= FTS_PHYSICAL;
546 else
547 fts_flags |= FTS_LOGICAL;
548
549 fts = fts_open((char * const *)paths, fts_flags, NULL);
550
551 status = s->statuscb;
552 while ((ftsent = fts_read(fts)) != NULL) {
553 int rv = 0;
554 char *dstfile = NULL;
555 int cmd = 0;
556 copyfile_state_t tstate = copyfile_state_alloc();
557 if (tstate == NULL) {
558 errno = ENOMEM;
559 retval = -1;
560 break;
561 }
562 tstate->statuscb = s->statuscb;
563 tstate->ctx = s->ctx;
564 asprintf(&dstfile, "%s%s%s", dst, dstpathsep, ftsent->fts_path + offset);
565 if (dstfile == NULL) {
566 copyfile_state_free(tstate);
567 errno = ENOMEM;
568 retval = -1;
569 break;
570 }
571 switch (ftsent->fts_info) {
572 case FTS_D:
573 tstate->internal_flags |= cfDelayAce;
574 cmd = COPYFILE_RECURSE_DIR;
575 break;
576 case FTS_SL:
577 case FTS_SLNONE:
578 case FTS_DEFAULT:
579 case FTS_F:
580 cmd = COPYFILE_RECURSE_FILE;
581 break;
582 case FTS_DP:
583 cmd = COPYFILE_RECURSE_DIR_CLEANUP;
584 break;
585 case FTS_DNR:
586 case FTS_ERR:
587 case FTS_NS:
588 case FTS_NSOK:
589 default:
590 errno = ftsent->fts_errno;
591 if (status) {
592 rv = (*status)(COPYFILE_RECURSE_ERROR, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
593 if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
594 errno = 0;
595 goto skipit;
596 }
597 if (rv == COPYFILE_QUIT) {
598 retval = -1;
599 goto stopit;
600 }
601 } else {
602 retval = -1;
603 goto stopit;
604 }
605 case FTS_DOT:
606 goto skipit;
607
608 }
609
610 if (cmd == COPYFILE_RECURSE_DIR || cmd == COPYFILE_RECURSE_FILE) {
611 if (status) {
612 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
613 if (rv == COPYFILE_SKIP) {
614 if (cmd == COPYFILE_RECURSE_DIR) {
615 rv = fts_set(fts, ftsent, FTS_SKIP);
616 if (rv == -1) {
617 rv = (*status)(0, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
618 if (rv == COPYFILE_QUIT)
619 retval = -1;
620 }
621 }
622 goto skipit;
623 }
624 if (rv == COPYFILE_QUIT) {
625 retval = -1; errno = 0;
626 goto stopit;
627 }
628 }
629 rv = copyfile(ftsent->fts_path, dstfile, tstate, flags);
630 if (rv < 0) {
631 if (status) {
632 rv = (*status)(cmd, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
633 if (rv == COPYFILE_QUIT) {
634 retval = -1;
635 goto stopit;
636 } else
637 rv = 0;
638 goto skipit;
639 } else {
640 retval = -1;
641 goto stopit;
642 }
643 }
644 if (status) {
645 rv = (*status)(cmd, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
646 if (rv == COPYFILE_QUIT) {
647 retval = -1; errno = 0;
648 goto stopit;
649 }
650 }
651 } else if (cmd == COPYFILE_RECURSE_DIR_CLEANUP) {
652 int tfd;
653
654 if (status) {
655 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
656 if (rv == COPYFILE_QUIT) {
657 retval = -1; errno = 0;
658 goto stopit;
659 } else if (rv == COPYFILE_SKIP) {
660 rv = 0;
661 goto skipit;
662 }
663 }
664 tfd = open(dstfile, O_RDONLY);
665 if (tfd != -1) {
666 struct stat sb;
667 if (s->flags & COPYFILE_STAT) {
668 (s->flags & COPYFILE_NOFOLLOW_SRC ? lstat : stat)(ftsent->fts_path, &sb);
669 } else {
670 (s->flags & COPYFILE_NOFOLLOW_DST ? lstat : stat)(dstfile, &sb);
671 }
672 remove_uberace(tfd, &sb);
673 close(tfd);
674 if (status) {
675 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
676 if (rv == COPYFILE_QUIT) {
677 rv = -1; errno = 0;
678 goto stopit;
679 }
680 }
681 } else {
682 if (status) {
683 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
684 if (rv == COPYFILE_QUIT) {
685 retval = -1;
686 goto stopit;
687 } else if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
688 if (rv == COPYFILE_CONTINUE)
689 errno = 0;
690 retval = 0;
691 goto skipit;
692 }
693 } else {
694 retval = -1;
695 goto stopit;
696 }
697 }
698 rv = 0;
699 }
700 skipit:
701 stopit:
702 copyfile_state_free(tstate);
703 free(dstfile);
704 if (retval == -1)
705 break;
706 }
707
708 done:
709 if (fts)
710 fts_close(fts);
711
712 return retval;
713 }
714
715 /*
716 * fcopyfile() is used to copy a source file descriptor to a destination file
717 * descriptor. This allows an application to figure out how it wants to open
718 * the files (doing various security checks, perhaps), and then just pass in
719 * the file descriptors.
720 */
721 int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags)
722 {
723 int ret = 0;
724 copyfile_state_t s = state;
725 struct stat dst_sb;
726
727 if (src_fd < 0 || dst_fd < 0)
728 {
729 errno = EINVAL;
730 return -1;
731 }
732
733 if (copyfile_preamble(&s, flags) < 0)
734 return -1;
735
736 copyfile_debug(2, "set src_fd <- %d", src_fd);
737 if (s->src_fd == -2 && src_fd > -1)
738 {
739 s->src_fd = src_fd;
740 if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0)
741 {
742 if (errno == ENOTSUP || errno == EPERM)
743 fstat(s->src_fd, &s->sb);
744 else
745 {
746 copyfile_warn("fstatx_np on src fd %d", s->src_fd);
747 return -1;
748 }
749 }
750 }
751
752 /* prevent copying on unsupported types */
753 switch (s->sb.st_mode & S_IFMT)
754 {
755 case S_IFLNK:
756 case S_IFDIR:
757 case S_IFREG:
758 break;
759 default:
760 errno = ENOTSUP;
761 return -1;
762 }
763
764 copyfile_debug(2, "set dst_fd <- %d", dst_fd);
765 if (s->dst_fd == -2 && dst_fd > -1)
766 s->dst_fd = dst_fd;
767
768 (void)fstat(s->dst_fd, &dst_sb);
769 (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR));
770
771 (void)copyfile_quarantine(s);
772
773 ret = copyfile_internal(s, flags);
774
775 if (ret >= 0 && !(s->flags & COPYFILE_STAT))
776 {
777 (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT);
778 }
779
780 if (s->err) {
781 errno = s->err;
782 s->err = 0;
783 }
784 if (state == NULL) {
785 int t = errno;
786 copyfile_state_free(s);
787 errno = t;
788 }
789
790 return ret;
791
792 }
793
794 /*
795 * the original copyfile() routine; this copies a source file to a destination
796 * file. Note that because we need to set the names in the state variable, this
797 * is not just the same as opening the two files, and then calling fcopyfile().
798 * Oh, if only life were that simple!
799 */
800 int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags)
801 {
802 int ret = 0;
803 int createdst = 0;
804 copyfile_state_t s = state;
805 struct stat dst_sb;
806
807 if (src == NULL && dst == NULL)
808 {
809 errno = EINVAL;
810 return -1;
811 }
812
813 if (copyfile_preamble(&s, flags) < 0)
814 {
815 return -1;
816 }
817
818 /*
819 * This macro is... well, it's not the worst thing you can do with cpp, not
820 * by a long shot. Essentially, we are setting the filename (src or dst)
821 * in the state structure; since the structure may not have been cleared out
822 * before being used again, we do some of the cleanup here: if the given
823 * filename (e.g., src) is set, and state->src is not equal to that, then
824 * we need to check to see if the file descriptor had been opened, and if so,
825 * close it. After that, we set state->src to be a copy of the given filename,
826 * releasing the old copy if necessary.
827 */
828 #define COPYFILE_SET_FNAME(NAME, S) \
829 do { \
830 if (NAME != NULL) { \
831 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
832 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
833 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
834 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
835 close(S->NAME##_fd); \
836 S->NAME##_fd = -2; \
837 } \
838 } \
839 if (S->NAME) { \
840 free(S->NAME); \
841 S->NAME = NULL; \
842 } \
843 if ((S->NAME = strdup(NAME)) == NULL) \
844 return -1; \
845 } \
846 } while (0)
847
848 COPYFILE_SET_FNAME(src, s);
849 COPYFILE_SET_FNAME(dst, s);
850
851 if (s->flags & COPYFILE_RECURSIVE) {
852 ret = copytree(s);
853 goto exit;
854 }
855
856 /*
857 * Get a copy of the source file's security settings
858 */
859 if ((s->original_fsec = filesec_init()) == NULL)
860 goto error_exit;
861
862 if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 &&
863 (dst_sb.st_mode & S_IFLNK)) {
864 if (s->permissive_fsec)
865 free(s->permissive_fsec);
866 s->permissive_fsec = NULL;
867 } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0)
868 {
869 /*
870 * copyfile_fix_perms() will make a copy of the permission set,
871 * and insert at the beginning an ACE that ensures we can write
872 * to the file and set attributes.
873 */
874
875 if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL)
876 {
877 /*
878 * Set the permissions for the destination to our copy.
879 * We should get ENOTSUP from any filesystem that simply
880 * doesn't support it.
881 */
882 if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP)
883 {
884 copyfile_warn("setting security information");
885 filesec_free(s->permissive_fsec);
886 s->permissive_fsec = NULL;
887 }
888 }
889 } else if (errno == ENOENT) {
890 createdst = 1;
891 }
892
893 /*
894 * If COPYFILE_CHECK is set in flags, then all we are going to do
895 * is see what kinds of things WOULD have been copied (see
896 * copyfile_check() below). We return that value.
897 */
898 if (COPYFILE_CHECK & flags)
899 {
900 ret = copyfile_check(s);
901 goto exit;
902 } else if ((ret = copyfile_open(s)) < 0)
903 goto error_exit;
904
905 ret = copyfile_internal(s, flags);
906 if (ret == -1)
907 goto error_exit;
908
909 #ifdef COPYFILE_RECURSIVE
910 if (!(flags & COPYFILE_STAT)) {
911 if (!createdst)
912 {
913 /* Just need to reset the BSD information -- mode, owner, group */
914 (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid);
915 (void)fchmod(s->dst_fd, dst_sb.st_mode);
916 }
917 }
918 #endif
919
920 reset_security(s);
921
922 exit:
923 if (state == NULL) {
924 int t = errno;
925 copyfile_state_free(s);
926 errno = t;
927 }
928
929 return ret;
930
931 error_exit:
932 ret = -1;
933 if (s->err) {
934 errno = s->err;
935 s->err = 0;
936 }
937 goto exit;
938 }
939
940 /*
941 * Shared prelude to the {f,}copyfile(). This initializes the
942 * state variable, if necessary, and also checks for both debugging
943 * and disabling environment variables.
944 */
945 static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags)
946 {
947 copyfile_state_t s;
948
949 if (*state == NULL)
950 {
951 if ((*state = copyfile_state_alloc()) == NULL)
952 return -1;
953 }
954
955 s = *state;
956
957 if (COPYFILE_DEBUG & flags)
958 {
959 char *e;
960 if ((e = getenv(COPYFILE_DEBUG_VAR)))
961 {
962 errno = 0;
963 s->debug = (uint32_t)strtol(e, NULL, 0);
964
965 /* clamp s->debug to 1 if the environment variable is not parsable */
966 if (s->debug == 0 && errno != 0)
967 s->debug = 1;
968 }
969 copyfile_debug(2, "debug value set to: %d", s->debug);
970 }
971
972 #if 0
973 /* Temporarily disabled */
974 if (getenv(COPYFILE_DISABLE_VAR) != NULL)
975 {
976 copyfile_debug(1, "copyfile disabled");
977 return 2;
978 }
979 #endif
980 copyfile_debug(2, "setting flags: %d", s->flags);
981 s->flags = flags;
982
983 return 0;
984 }
985
986 /*
987 * The guts of {f,}copyfile().
988 * This looks through the flags in a particular order, and calls the
989 * associated functions.
990 */
991 static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags)
992 {
993 int ret = 0;
994
995 if (s->dst_fd < 0 || s->src_fd < 0)
996 {
997 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd);
998 s->err = EINVAL;
999 return -1;
1000 }
1001
1002 /*
1003 * COPYFILE_PACK causes us to create an Apple Double version of the
1004 * source file, and puts it into the destination file. See
1005 * copyfile_pack() below for all the gory details.
1006 */
1007 if (COPYFILE_PACK & flags)
1008 {
1009 if ((ret = copyfile_pack(s)) < 0)
1010 {
1011 if (s->dst) unlink(s->dst);
1012 goto exit;
1013 }
1014 goto exit;
1015 }
1016
1017 /*
1018 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1019 * The goal there is to take an Apple Double file, and turn it
1020 * into a normal file (with data fork, resource fork, modes,
1021 * extended attributes, ACLs, etc.).
1022 */
1023 if (COPYFILE_UNPACK & flags)
1024 {
1025 if ((ret = copyfile_unpack(s)) < 0)
1026 goto error_exit;
1027 goto exit;
1028 }
1029
1030 /*
1031 * If we have quarantine info set, we attempt
1032 * to apply it to dst_fd. We don't care if
1033 * it fails, not yet anyway.
1034 */
1035 if (s->qinfo)
1036 (void)qtn_file_apply_to_fd(s->qinfo, s->dst_fd);
1037
1038 /*
1039 * COPYFILE_XATTR tells us to copy the extended attributes;
1040 * this is seperate from the extended security (aka ACLs),
1041 * however. If we succeed in this, we continue to the next
1042 * stage; if we fail, we return with an error value. Note
1043 * that we fail if the errno is ENOTSUP, but we don't print
1044 * a warning in that case.
1045 */
1046 if (COPYFILE_XATTR & flags)
1047 {
1048 if ((ret = copyfile_xattr(s)) < 0)
1049 {
1050 if (errno != ENOTSUP && errno != EPERM)
1051 copyfile_warn("error processing extended attributes");
1052 goto exit;
1053 }
1054 }
1055
1056 /*
1057 * Simialr to above, this tells us whether or not to copy
1058 * the non-meta data portion of the file. We attempt to
1059 * remove (via unlink) the destination file if we fail.
1060 */
1061 if (COPYFILE_DATA & flags)
1062 {
1063 if ((ret = copyfile_data(s)) < 0)
1064 {
1065 copyfile_warn("error processing data");
1066 if (s->dst && unlink(s->dst))
1067 copyfile_warn("%s: remove", s->src ? s->src : "(null src)");
1068 goto exit;
1069 }
1070 }
1071
1072 /*
1073 * COPYFILE_SECURITY requests that we copy the security, both
1074 * extended and mundane (that is, ACLs and POSIX).
1075 */
1076 if (COPYFILE_SECURITY & flags)
1077 {
1078 if ((ret = copyfile_security(s)) < 0)
1079 {
1080 copyfile_warn("error processing security information");
1081 goto exit;
1082 }
1083 }
1084
1085 if (COPYFILE_STAT & flags)
1086 {
1087 if ((ret = copyfile_stat(s)) < 0)
1088 {
1089 copyfile_warn("error processing POSIX information");
1090 goto exit;
1091 }
1092 }
1093
1094 exit:
1095 return ret;
1096
1097 error_exit:
1098 ret = -1;
1099 goto exit;
1100 }
1101
1102 /*
1103 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1104 */
1105 copyfile_state_t copyfile_state_alloc(void)
1106 {
1107 copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state));
1108
1109 if (s != NULL)
1110 {
1111 s->src_fd = -2;
1112 s->dst_fd = -2;
1113 s->fsec = filesec_init();
1114 } else
1115 errno = ENOMEM;
1116
1117 return s;
1118 }
1119
1120 /*
1121 * copyfile_state_free() returns the memory allocated to the state structure.
1122 * It also closes the file descriptors, if they've been opened.
1123 */
1124 int copyfile_state_free(copyfile_state_t s)
1125 {
1126 if (s != NULL)
1127 {
1128 if (s->fsec)
1129 filesec_free(s->fsec);
1130
1131 if (s->original_fsec)
1132 filesec_free(s->original_fsec);
1133
1134 if (s->permissive_fsec)
1135 filesec_free(s->permissive_fsec);
1136
1137 if (s->qinfo)
1138 qtn_file_free(s->qinfo);
1139
1140 if (copyfile_close(s) < 0)
1141 {
1142 copyfile_warn("error closing files");
1143 return -1;
1144 }
1145 if (s->dst)
1146 free(s->dst);
1147 if (s->src)
1148 free(s->src);
1149 free(s);
1150 }
1151 return 0;
1152 }
1153
1154 /*
1155 * Should we worry if we can't close the source? NFS says we
1156 * should, but it's pretty late for us at this point.
1157 */
1158 static int copyfile_close(copyfile_state_t s)
1159 {
1160 if (s->src && s->src_fd >= 0)
1161 close(s->src_fd);
1162
1163 if (s->dst && s->dst_fd >= 0) {
1164 if (close(s->dst_fd))
1165 return -1;
1166 }
1167
1168 return 0;
1169 }
1170
1171 /*
1172 * The purpose of this function is to set up a set of permissions
1173 * (ACL and traditional) that lets us write to the file. In the
1174 * case of ACLs, we do this by putting in a first entry that lets
1175 * us write data, attributes, and extended attributes. In the case
1176 * of traditional permissions, we set the S_IWUSR (user-write)
1177 * bit.
1178 */
1179 static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec)
1180 {
1181 filesec_t ret_fsec = NULL;
1182 mode_t mode;
1183 acl_t acl = NULL;
1184
1185 if ((ret_fsec = filesec_dup(*fsec)) == NULL)
1186 goto error_exit;
1187
1188 if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0)
1189 {
1190 #ifdef COPYFILE_RECURSIVE
1191 if (add_uberace(&acl))
1192 goto error_exit;
1193 #else
1194 acl_entry_t entry;
1195 acl_permset_t permset;
1196 uuid_t qual;
1197
1198 if (mbr_uid_to_uuid(getuid(), qual) != 0)
1199 goto error_exit;
1200
1201 /*
1202 * First, we create an entry, and give it the special name
1203 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1204 * After that, we clear out all the permissions in it, and
1205 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1206 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1207 * the functionality, and put this into the ACL.
1208 */
1209 if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1)
1210 goto error_exit;
1211 if (acl_get_permset(entry, &permset) == -1)
1212 goto error_exit;
1213 if (acl_clear_perms(permset) == -1)
1214 goto error_exit;
1215 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
1216 goto error_exit;
1217 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
1218 goto error_exit;
1219 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
1220 goto error_exit;
1221 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
1222 goto error_exit;
1223
1224 if(acl_set_permset(entry, permset) == -1)
1225 goto error_exit;
1226 if(acl_set_qualifier(entry, qual) == -1)
1227 goto error_exit;
1228 #endif
1229
1230 if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0)
1231 goto error_exit;
1232 }
1233
1234 /*
1235 * This is for the normal, mundane, POSIX permission model.
1236 * We make sure that we can write to the file.
1237 */
1238 if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0)
1239 {
1240 if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR))
1241 {
1242 mode |= S_IWUSR|S_IRUSR;
1243 if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0)
1244 goto error_exit;
1245 }
1246 }
1247
1248 exit:
1249 if (acl)
1250 acl_free(acl);
1251
1252 return ret_fsec;
1253
1254 error_exit:
1255 if (ret_fsec)
1256 {
1257 filesec_free(ret_fsec);
1258 ret_fsec = NULL;
1259 }
1260 goto exit;
1261 }
1262
1263 /*
1264 * Used to clear out the BSD/POSIX security information from
1265 * a filesec
1266 */
1267 static int
1268 copyfile_unset_posix_fsec(filesec_t fsec)
1269 {
1270 (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY);
1271 (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY);
1272 (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY);
1273 return 0;
1274 }
1275
1276 /*
1277 * Used to remove acl information from a filesec_t
1278 * Unsetting the acl alone in Tiger was insufficient
1279 */
1280 static int copyfile_unset_acl(copyfile_state_t s)
1281 {
1282 int ret = 0;
1283 if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1)
1284 {
1285 copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)");
1286 ++ret;
1287 }
1288 if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1)
1289 {
1290 copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1291 ++ret;
1292 }
1293 if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1)
1294 {
1295 copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1296 ++ret;
1297 }
1298 return ret;
1299 }
1300
1301 /*
1302 * copyfile_open() does what one expects: it opens up the files
1303 * given in the state structure, if they're not already open.
1304 * It also does some type validation, to ensure that we only
1305 * handle file types we know about.
1306 */
1307 static int copyfile_open(copyfile_state_t s)
1308 {
1309 int oflags = O_EXCL | O_CREAT | O_WRONLY;
1310 int islnk = 0, isdir = 0;
1311 int osrc = 0, dsrc = 0;
1312
1313 if (s->src && s->src_fd == -2)
1314 {
1315 if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1316 (s->src, &s->sb, s->fsec))
1317 {
1318 copyfile_warn("stat on %s", s->src);
1319 return -1;
1320 }
1321
1322 /* prevent copying on unsupported types */
1323 switch (s->sb.st_mode & S_IFMT)
1324 {
1325 case S_IFLNK:
1326 islnk = 1;
1327 if ((size_t)s->sb.st_size > SIZE_T_MAX) {
1328 s->err = ENOMEM; /* too big for us to copy */
1329 return -1;
1330 }
1331 osrc = O_SYMLINK;
1332 break;
1333 case S_IFDIR:
1334 isdir = 1;
1335 break;
1336 case S_IFREG:
1337 break;
1338 default:
1339 if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) {
1340 s->err = ENOTSUP;
1341 return -1;
1342 }
1343 }
1344 /*
1345 * If we're packing, then we are actually
1346 * creating a file, no matter what the source
1347 * was.
1348 */
1349 if (s->flags & COPYFILE_PACK) {
1350 /*
1351 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1352 * if the file is a symlink, and O_NOFOLLOW is specified,
1353 * open will return ELOOP, whether or not O_SYMLINK is set.
1354 * However, we know whether or not it was a symlink from
1355 * the stat above (although there is a potentiaal for a race
1356 * condition here, but it will err on the side of returning
1357 * ELOOP from open).
1358 */
1359 if (!islnk)
1360 osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0;
1361 isdir = islnk = 0;
1362 }
1363
1364 if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0)
1365 {
1366 copyfile_warn("open on %s", s->src);
1367 return -1;
1368 } else
1369 copyfile_debug(2, "open successful on source (%s)", s->src);
1370
1371 (void)copyfile_quarantine(s);
1372 }
1373
1374 if (s->dst && s->dst_fd == -2)
1375 {
1376 /*
1377 * COPYFILE_UNLINK tells us to try removing the destination
1378 * before we create it. We don't care if the file doesn't
1379 * exist, so we ignore ENOENT.
1380 */
1381 if (COPYFILE_UNLINK & s->flags)
1382 {
1383 if (remove(s->dst) < 0 && errno != ENOENT)
1384 {
1385 copyfile_warn("%s: remove", s->dst);
1386 return -1;
1387 }
1388 }
1389
1390 if (s->flags & COPYFILE_NOFOLLOW_DST) {
1391 struct stat st;
1392
1393 dsrc = O_NOFOLLOW;
1394 if (lstat(s->dst, &st) != -1) {
1395 if ((st.st_mode & S_IFMT) == S_IFLNK)
1396 dsrc = O_SYMLINK;
1397 }
1398 }
1399
1400 if (islnk) {
1401 size_t sz = (size_t)s->sb.st_size + 1;
1402 char *bp;
1403
1404 bp = calloc(1, sz);
1405 if (bp == NULL) {
1406 copyfile_warn("cannot allocate %d bytes", sz);
1407 return -1;
1408 }
1409 if (readlink(s->src, bp, sz-1) == -1) {
1410 copyfile_warn("cannot readlink %s", s->src);
1411 free(bp);
1412 return -1;
1413 }
1414 if (symlink(bp, s->dst) == -1) {
1415 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1416 copyfile_warn("Cannot make symlink %s", s->dst);
1417 free(bp);
1418 return -1;
1419 }
1420 }
1421 free(bp);
1422 s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK);
1423 if (s->dst_fd == -1) {
1424 copyfile_warn("Cannot open symlink %s for reading", s->dst);
1425 return -1;
1426 }
1427 } else if (isdir) {
1428 mode_t mode;
1429 mode = s->sb.st_mode & ~S_IFMT;
1430
1431 if (mkdir(s->dst, mode) == -1) {
1432 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1433 copyfile_warn("Cannot make directory %s", s->dst);
1434 return -1;
1435 }
1436 }
1437 s->dst_fd = open(s->dst, O_RDONLY | dsrc);
1438 if (s->dst_fd == -1) {
1439 copyfile_warn("Cannot open directory %s for reading", s->dst);
1440 return -1;
1441 }
1442 } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0)
1443 {
1444 /*
1445 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1446 * was written -- allow one to set an extended attribute on a file descriptor
1447 * for a read-only file, even if the file descriptor is opened for writing.
1448 * This will only matter if the file does not already exist.
1449 */
1450 switch(errno)
1451 {
1452 case EEXIST:
1453 copyfile_debug(3, "open failed, retrying (%s)", s->dst);
1454 if (s->flags & COPYFILE_EXCL)
1455 break;
1456 oflags = oflags & ~O_CREAT;
1457 if (s->flags & (COPYFILE_PACK | COPYFILE_DATA))
1458 {
1459 copyfile_debug(4, "truncating existing file (%s)", s->dst);
1460 oflags |= O_TRUNC;
1461 }
1462 continue;
1463 case EACCES:
1464 if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0)
1465 continue;
1466 else {
1467 /*
1468 * If we're trying to write to a directory to which we don't
1469 * have access, the create above would have failed, but chmod
1470 * here would have given us ENOENT. But the real error is
1471 * still one of access, so we change the errno we're reporting.
1472 * This could cause confusion with a race condition.
1473 */
1474
1475 if (errno == ENOENT)
1476 errno = EACCES;
1477 break;
1478 }
1479 case EISDIR:
1480 copyfile_debug(3, "open failed because it is a directory (%s)", s->dst);
1481 if ((s->flags & COPYFILE_EXCL) ||
1482 (!isdir && (s->flags & COPYFILE_DATA)))
1483 break;
1484 oflags = (oflags & ~O_WRONLY) | O_RDONLY;
1485 continue;
1486 }
1487 copyfile_warn("open on %s", s->dst);
1488 return -1;
1489 }
1490 copyfile_debug(2, "open successful on destination (%s)", s->dst);
1491 }
1492
1493 if (s->dst_fd < 0 || s->src_fd < 0)
1494 {
1495 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1496 s->src_fd, s->dst_fd);
1497 s->err = EINVAL;
1498 return -1;
1499 }
1500 return 0;
1501 }
1502
1503
1504 /*
1505 * copyfile_check(), as described above, essentially tells you
1506 * what you'd have to copy, if you wanted it to copy the things
1507 * you asked it to copy.
1508 * In other words, if you pass in COPYFILE_ALL, and the file in
1509 * question had no extended attributes but did have an ACL, you'd
1510 * get back COPYFILE_ACL.
1511 */
1512 static copyfile_flags_t copyfile_check(copyfile_state_t s)
1513 {
1514 acl_t acl = NULL;
1515 copyfile_flags_t ret = 0;
1516 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
1517 qtn_file_t qinfo;
1518
1519 if (!s->src)
1520 {
1521 s->err = EINVAL;
1522 return -1;
1523 }
1524
1525 /* check EAs */
1526 if (COPYFILE_XATTR & s->flags)
1527 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
1528 {
1529 ret |= COPYFILE_XATTR;
1530 }
1531
1532 if (COPYFILE_ACL & s->flags)
1533 {
1534 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1535 (s->src, &s->sb, s->fsec);
1536
1537 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
1538 ret |= COPYFILE_ACL;
1539 }
1540
1541 copyfile_debug(2, "check result: %d (%s)", ret, s->src);
1542
1543 if (acl)
1544 acl_free(acl);
1545
1546 if (s->qinfo) {
1547 /* If the state has had quarantine info set already, we use that */
1548 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1549 } else {
1550 qinfo = qtn_file_alloc();
1551 /*
1552 * For quarantine information, we need to see if the source file
1553 * has any. Since it may be a symlink, however, and we may, or
1554 * not be following, *and* there's no qtn* routine which can optionally
1555 * follow or not follow a symlink, we need to instead work around
1556 * this limitation.
1557 */
1558 if (qinfo) {
1559 int fd;
1560 int qret = 0;
1561 struct stat sbuf;
1562
1563 /*
1564 * If we care about not following symlinks, *and* the file exists
1565 * (which is to say, lstat doesn't return an error), *and* the file
1566 * is a symlink, then we open it up (with O_SYMLINK), and use
1567 * qtn_file_init_with_fd(); if none of that is true, however, then
1568 * we can simply use qtn_file_init_with_path().
1569 */
1570 if (nofollow
1571 && lstat(s->src, &sbuf) == 0
1572 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
1573 fd = open(s->src, O_RDONLY | O_SYMLINK);
1574 if (fd != -1) {
1575 if (!qtn_file_init_with_fd(qinfo, fd)) {
1576 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1577 }
1578 close(fd);
1579 }
1580 } else {
1581 if (!qtn_file_init_with_path(qinfo, s->src)) {
1582 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1583 }
1584 }
1585 qtn_file_free(qinfo);
1586 ret |= qret;
1587 }
1588 }
1589 return ret;
1590 }
1591
1592 /*
1593 * Attempt to copy the data section of a file. Using blockisize
1594 * is not necessarily the fastest -- it might be desirable to
1595 * specify a blocksize, somehow. But it's a size that should be
1596 * guaranteed to work.
1597 */
1598 static int copyfile_data(copyfile_state_t s)
1599 {
1600 size_t blen;
1601 char *bp = 0;
1602 ssize_t nread;
1603 int ret = 0;
1604 size_t iBlocksize = 0;
1605 size_t oBlocksize = 0;
1606 const size_t onegig = 1 << 30;
1607 struct statfs sfs;
1608 copyfile_callback_t status = s->statuscb;
1609
1610 /* Unless it's a normal file, we don't copy. For now, anyway */
1611 if ((s->sb.st_mode & S_IFMT) != S_IFREG)
1612 return 0;
1613
1614 if (fstatfs(s->src_fd, &sfs) == -1) {
1615 iBlocksize = s->sb.st_blksize;
1616 } else {
1617 iBlocksize = sfs.f_iosize;
1618 }
1619
1620 /* Work-around for 6453525, limit blocksize to 1G */
1621 if (iBlocksize > onegig) {
1622 iBlocksize = onegig;
1623 }
1624
1625 if ((bp = malloc(iBlocksize)) == NULL)
1626 return -1;
1627
1628 if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) {
1629 oBlocksize = iBlocksize;
1630 } else {
1631 oBlocksize = sfs.f_iosize;
1632 if (oBlocksize > onegig)
1633 oBlocksize = onegig;
1634 }
1635
1636 blen = iBlocksize;
1637
1638 s->totalCopied = 0;
1639 /* If supported, do preallocation for Xsan / HFS volumes */
1640 #ifdef F_PREALLOCATE
1641 {
1642 fstore_t fst;
1643
1644 fst.fst_flags = 0;
1645 fst.fst_posmode = F_PEOFPOSMODE;
1646 fst.fst_offset = 0;
1647 fst.fst_length = s->sb.st_size;
1648 /* Ignore errors; this is merely advisory. */
1649 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
1650 }
1651 #endif
1652
1653 while ((nread = read(s->src_fd, bp, blen)) > 0)
1654 {
1655 ssize_t nwritten;
1656 size_t left = nread;
1657 void *ptr = bp;
1658 int loop = 0;
1659
1660 while (left > 0) {
1661 nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize));
1662 switch (nwritten) {
1663 case 0:
1664 if (++loop > 5) {
1665 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
1666 ret = -1;
1667 s->err = EAGAIN;
1668 goto exit;
1669 }
1670 break;
1671 case -1:
1672 copyfile_warn("writing to output file got error");
1673 if (status) {
1674 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1675 if (rv == COPYFILE_SKIP) { // Skip the data copy
1676 ret = 0;
1677 goto exit;
1678 }
1679 if (rv == COPYFILE_CONTINUE) { // Retry the write
1680 errno = 0;
1681 continue;
1682 }
1683 }
1684 ret = -1;
1685 goto exit;
1686 default:
1687 left -= nwritten;
1688 ptr = ((char*)ptr) + nwritten;
1689 loop = 0;
1690 break;
1691 }
1692 s->totalCopied += nwritten;
1693 if (status) {
1694 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
1695 if (rv == COPYFILE_QUIT) {
1696 ret = -1; s->err = ECANCELED;
1697 goto exit;
1698 }
1699 }
1700 }
1701 }
1702 if (nread < 0)
1703 {
1704 copyfile_warn("reading from %s", s->src ? s->src : "(null src)");
1705 ret = -1;
1706 goto exit;
1707 }
1708
1709 if (ftruncate(s->dst_fd, s->sb.st_size) < 0)
1710 {
1711 ret = -1;
1712 goto exit;
1713 }
1714
1715 exit:
1716 if (ret == -1)
1717 {
1718 s->err = errno;
1719 }
1720 free(bp);
1721 return ret;
1722 }
1723
1724 /*
1725 * copyfile_security() will copy the ACL set, and the
1726 * POSIX set. Complexities come when dealing with
1727 * inheritied permissions, and when dealing with both
1728 * POSIX and ACL permissions.
1729 */
1730 static int copyfile_security(copyfile_state_t s)
1731 {
1732 int copied = 0;
1733 int has_uberace = 0;
1734 acl_flagset_t flags;
1735 struct stat sb;
1736 acl_entry_t entry_src = NULL, entry_dst = NULL;
1737 acl_t acl_src = NULL, acl_dst = NULL;
1738 int ret = 0;
1739 filesec_t tmp_fsec = NULL;
1740 filesec_t fsec_dst = filesec_init();
1741
1742 if (fsec_dst == NULL)
1743 return -1;
1744
1745
1746 if (COPYFILE_ACL & s->flags)
1747 {
1748 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
1749 {
1750 if (errno == ENOENT)
1751 acl_src = NULL;
1752 else
1753 goto error_exit;
1754 }
1755
1756 /* grab the destination acl
1757 cannot assume it's empty due to inheritance
1758 */
1759 if(fstatx_np(s->dst_fd, &sb, fsec_dst))
1760 goto error_exit;
1761
1762 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
1763 {
1764 if (errno == ENOENT)
1765 acl_dst = NULL;
1766 else
1767 goto error_exit;
1768 }
1769 else
1770 {
1771 acl_t tmp = acl_init(4);
1772 acl_entry_t ace = NULL;
1773 int count = 0;
1774
1775 if (tmp == NULL)
1776 goto error_exit;
1777
1778
1779 for (; acl_get_entry(acl_dst,
1780 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1781 &ace) == 0;)
1782 {
1783 if (count++ == 0 && is_uberace(ace)) {
1784 if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
1785 break;
1786 if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
1787 break;
1788 has_uberace = 1;
1789 continue;
1790 }
1791 acl_get_flagset_np(ace, &flags);
1792 if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1793 {
1794 if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
1795 break;
1796 if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
1797 break;
1798 }
1799 }
1800 acl_free(acl_dst);
1801 acl_dst = tmp;
1802
1803 if (ret == -1)
1804 goto error_exit;
1805 }
1806
1807 if (acl_src == NULL && acl_dst == NULL)
1808 goto no_acl;
1809
1810 if (acl_src) {
1811 if (acl_dst == NULL)
1812 acl_dst = acl_init(4);
1813 for (copied = 0;acl_get_entry(acl_src,
1814 entry_src == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1815 &entry_src) == 0;)
1816 {
1817 acl_get_flagset_np(entry_src, &flags);
1818 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1819 {
1820 if ((ret = acl_create_entry(&acl_dst, &entry_dst)) == -1)
1821 goto error_exit;
1822
1823 if ((ret = acl_copy_entry(entry_dst, entry_src)) == -1)
1824 goto error_exit;
1825
1826 copyfile_debug(2, "copied acl entry from %s to %s",
1827 s->src ? s->src : "(null src)",
1828 s->dst ? s->dst : "(null dst)");
1829 copied++;
1830 }
1831 }
1832 }
1833 if (!has_uberace && (s->internal_flags & cfDelayAce)) {
1834 if (add_uberace(&acl_dst))
1835 goto error_exit;
1836 }
1837 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_dst))
1838 {
1839 copyfile_debug(3, "altered acl");
1840 }
1841 }
1842 no_acl:
1843 /*
1844 * The following code is attempting to ensure that only the requested
1845 * security information gets copied over to the destination file.
1846 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
1847 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
1848 * this function).
1849 *
1850 * If we have both flags, we copy everything; if we have ACL but not STAT,
1851 * we remove the POSIX information from the filesec object, and apply the
1852 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
1853 * the extended version.
1854 */
1855 tmp_fsec = filesec_dup(s->fsec);
1856 if (tmp_fsec == NULL) {
1857 goto error_exit;
1858 }
1859
1860 switch (COPYFILE_SECURITY & s->flags) {
1861 case COPYFILE_ACL:
1862 copyfile_unset_posix_fsec(tmp_fsec);
1863 /* FALLTHROUGH */
1864 case COPYFILE_ACL | COPYFILE_STAT:
1865 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
1866 acl_t acl = NULL;
1867 /*
1868 * The call could have failed for a number of reasons, since
1869 * it does a number of things: it changes the mode of the file,
1870 * sets the owner and group, and applies an ACL (if one exists).
1871 * The typical failure is going to be trying to set the group of
1872 * the destination file to match the source file, when the process
1873 * doesn't have permission to put files in that group. We try to
1874 * work around this by breaking the steps out and doing them
1875 * discretely. We don't care if the fchown fails, but we do care
1876 * if the mode or ACL can't be set. For historical reasons, we
1877 * simply log those failures, however.
1878 */
1879
1880 #define NS(x) ((x) ? (x) : "(null string)")
1881 if (fchmod(s->dst_fd, s->sb.st_mode) == -1) {
1882 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src));
1883 }
1884 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
1885 if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) {
1886 if (acl_set_fd(s->dst_fd, acl) == -1) {
1887 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src));
1888 }
1889 acl_free(acl);
1890 }
1891 }
1892 #undef NS
1893 break;
1894 case COPYFILE_STAT:
1895 (void)fchmod(s->dst_fd, s->sb.st_mode);
1896 break;
1897 }
1898 filesec_free(tmp_fsec);
1899 exit:
1900 filesec_free(fsec_dst);
1901 if (acl_src) acl_free(acl_src);
1902 if (acl_dst) acl_free(acl_dst);
1903
1904 return ret;
1905
1906 error_exit:
1907 ret = -1;
1908 goto exit;
1909
1910 }
1911
1912 /*
1913 * Attempt to set the destination file's stat information -- including
1914 * flags and time-related fields -- to the source's.
1915 */
1916 static int copyfile_stat(copyfile_state_t s)
1917 {
1918 struct timeval tval[2];
1919 /*
1920 * NFS doesn't support chflags; ignore errors unless there's reason
1921 * to believe we're losing bits. (Note, this still won't be right
1922 * if the server supports flags and we were trying to *remove* flags
1923 * on a file that we copied, i.e., that we didn't create.)
1924 */
1925 if (fchflags(s->dst_fd, (u_int)s->sb.st_flags))
1926 if (errno != EOPNOTSUPP || s->sb.st_flags != 0)
1927 copyfile_warn("%s: set flags (was: 0%07o)", s->dst ? s->dst : "(null dst)", s->sb.st_flags);
1928
1929 /* If this fails, we don't care */
1930 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
1931
1932 /* This may have already been done in copyfile_security() */
1933 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
1934
1935 tval[0].tv_sec = s->sb.st_atime;
1936 tval[1].tv_sec = s->sb.st_mtime;
1937 tval[0].tv_usec = tval[1].tv_usec = 0;
1938 if (futimes(s->dst_fd, tval))
1939 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
1940 return 0;
1941 }
1942
1943 /*
1944 * Similar to copyfile_security() in some ways; this
1945 * routine copies the extended attributes from the source,
1946 * and sets them on the destination.
1947 * The procedure is pretty simple, even if it is verbose:
1948 * for each named attribute on the destination, get its name, and
1949 * remove it. We should have none after that.
1950 * For each named attribute on the source, get its name, get its
1951 * data, and set it on the destination.
1952 */
1953 static int copyfile_xattr(copyfile_state_t s)
1954 {
1955 char *name;
1956 char *namebuf, *end;
1957 ssize_t xa_size;
1958 void *xa_dataptr;
1959 ssize_t bufsize = 4096;
1960 ssize_t asize;
1961 ssize_t nsize;
1962 int ret = 0;
1963
1964 /* delete EAs on destination */
1965 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
1966 {
1967 if ((namebuf = (char *) malloc(nsize)) == NULL)
1968 return -1;
1969 else
1970 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
1971
1972 if (nsize > 0) {
1973 /*
1974 * With this, end points to the last byte of the allocated buffer
1975 * This *should* be NUL, from flistxattr, but if it's not, we can
1976 * set it anyway -- it'll result in a truncated name, which then
1977 * shouldn't match when we get them later.
1978 */
1979 end = namebuf + nsize - 1;
1980 if (*end != 0)
1981 *end = 0;
1982 for (name = namebuf; name <= end; name += strlen(name) + 1) {
1983 /* If the quarantine information shows up as an EA, we skip over it */
1984 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
1985 continue;
1986 }
1987 fremovexattr(s->dst_fd, name,0);
1988 }
1989 }
1990 free(namebuf);
1991 } else
1992 if (nsize < 0)
1993 {
1994 if (errno == ENOTSUP || errno == EPERM)
1995 return 0;
1996 else
1997 return -1;
1998 }
1999
2000 /* get name list of EAs on source */
2001 if ((nsize = flistxattr(s->src_fd, 0, 0, 0)) < 0)
2002 {
2003 if (errno == ENOTSUP || errno == EPERM)
2004 return 0;
2005 else
2006 return -1;
2007 } else
2008 if (nsize == 0)
2009 return 0;
2010
2011 if ((namebuf = (char *) malloc(nsize)) == NULL)
2012 return -1;
2013 else
2014 nsize = flistxattr(s->src_fd, namebuf, nsize, 0);
2015
2016 if (nsize <= 0) {
2017 free(namebuf);
2018 return (int)nsize;
2019 }
2020
2021 /*
2022 * With this, end points to the last byte of the allocated buffer
2023 * This *should* be NUL, from flistxattr, but if it's not, we can
2024 * set it anyway -- it'll result in a truncated name, which then
2025 * shouldn't match when we get them later.
2026 */
2027 end = namebuf + nsize - 1;
2028 if (*end != 0)
2029 *end = 0;
2030
2031 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
2032 free(namebuf);
2033 return -1;
2034 }
2035
2036 for (name = namebuf; name <= end; name += strlen(name) + 1)
2037 {
2038 /* If the quarantine information shows up as an EA, we skip over it */
2039 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
2040 continue;
2041
2042 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, 0)) < 0)
2043 {
2044 ret = -1;
2045 continue;
2046 }
2047
2048 if (xa_size > bufsize)
2049 {
2050 void *tdptr = xa_dataptr;
2051 bufsize = xa_size;
2052 if ((xa_dataptr =
2053 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
2054 {
2055 free(tdptr);
2056 ret = -1;
2057 continue;
2058 }
2059 }
2060
2061 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, 0)) < 0)
2062 {
2063 ret = -1;
2064 continue;
2065 }
2066
2067 if (xa_size != asize)
2068 xa_size = asize;
2069
2070 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, 0) < 0)
2071 {
2072 ret = -1;
2073 continue;
2074 }
2075 }
2076 if (namebuf)
2077 free(namebuf);
2078 free((void *) xa_dataptr);
2079 return ret;
2080 }
2081
2082 /*
2083 * API interface into getting data from the opaque data type.
2084 */
2085 int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
2086 {
2087 if (ret == NULL)
2088 {
2089 errno = EFAULT;
2090 return -1;
2091 }
2092
2093 switch(flag)
2094 {
2095 case COPYFILE_STATE_SRC_FD:
2096 *(int*)ret = s->src_fd;
2097 break;
2098 case COPYFILE_STATE_DST_FD:
2099 *(int*)ret = s->dst_fd;
2100 break;
2101 case COPYFILE_STATE_SRC_FILENAME:
2102 *(char**)ret = s->src;
2103 break;
2104 case COPYFILE_STATE_DST_FILENAME:
2105 *(char**)ret = s->dst;
2106 break;
2107 case COPYFILE_STATE_QUARANTINE:
2108 *(qtn_file_t*)ret = s->qinfo;
2109 break;
2110 #if 0
2111 case COPYFILE_STATE_STATS:
2112 ret = s->stats.global;
2113 break;
2114 case COPYFILE_STATE_PROGRESS_CB:
2115 ret = s->callbacks.progress;
2116 break;
2117 #endif
2118 #ifdef COPYFILE_STATE_STATUS_CB
2119 case COPYFILE_STATE_STATUS_CB:
2120 *(copyfile_callback_t*)ret = s->statuscb;
2121 break;
2122 case COPYFILE_STATE_STATUS_CTX:
2123 *(void**)ret = s->ctx;
2124 break;
2125 case COPYFILE_STATE_COPIED:
2126 *(off_t*)ret = s->totalCopied;
2127 break;
2128 #endif
2129 default:
2130 errno = EINVAL;
2131 ret = NULL;
2132 return -1;
2133 }
2134 return 0;
2135 }
2136
2137 /*
2138 * Public API for setting state data (remember that the state is
2139 * an opaque data type).
2140 */
2141 int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
2142 {
2143 #define copyfile_set_string(DST, SRC) \
2144 do { \
2145 if (SRC != NULL) { \
2146 DST = strdup((char *)SRC); \
2147 } else { \
2148 if (DST != NULL) { \
2149 free(DST); \
2150 } \
2151 DST = NULL; \
2152 } \
2153 } while (0)
2154
2155 if (thing == NULL)
2156 {
2157 errno = EFAULT;
2158 return -1;
2159 }
2160
2161 switch(flag)
2162 {
2163 case COPYFILE_STATE_SRC_FD:
2164 s->src_fd = *(int*)thing;
2165 break;
2166 case COPYFILE_STATE_DST_FD:
2167 s->dst_fd = *(int*)thing;
2168 break;
2169 case COPYFILE_STATE_SRC_FILENAME:
2170 copyfile_set_string(s->src, thing);
2171 break;
2172 case COPYFILE_STATE_DST_FILENAME:
2173 copyfile_set_string(s->dst, thing);
2174 break;
2175 case COPYFILE_STATE_QUARANTINE:
2176 if (s->qinfo)
2177 {
2178 qtn_file_free(s->qinfo);
2179 s->qinfo = NULL;
2180 }
2181 if (*(qtn_file_t*)thing)
2182 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
2183 break;
2184 #if 0
2185 case COPYFILE_STATE_STATS:
2186 s->stats.global = thing;
2187 break;
2188 case COPYFILE_STATE_PROGRESS_CB:
2189 s->callbacks.progress = thing;
2190 break;
2191 #endif
2192 #ifdef COPYFILE_STATE_STATUS_CB
2193 case COPYFILE_STATE_STATUS_CB:
2194 s->statuscb = (copyfile_callback_t)thing;
2195 break;
2196 case COPYFILE_STATE_STATUS_CTX:
2197 s->ctx = (void*)thing;
2198 break;
2199 #endif
2200 default:
2201 errno = EINVAL;
2202 return -1;
2203 }
2204 return 0;
2205 #undef copyfile_set_string
2206 }
2207
2208
2209 /*
2210 * Make this a standalone program for testing purposes by
2211 * defining _COPYFILE_TEST.
2212 */
2213 #ifdef _COPYFILE_TEST
2214 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2215
2216 struct {char *s; int v;} opts[] = {
2217 COPYFILE_OPTION(ACL)
2218 COPYFILE_OPTION(STAT)
2219 COPYFILE_OPTION(XATTR)
2220 COPYFILE_OPTION(DATA)
2221 COPYFILE_OPTION(SECURITY)
2222 COPYFILE_OPTION(METADATA)
2223 COPYFILE_OPTION(ALL)
2224 COPYFILE_OPTION(NOFOLLOW_SRC)
2225 COPYFILE_OPTION(NOFOLLOW_DST)
2226 COPYFILE_OPTION(NOFOLLOW)
2227 COPYFILE_OPTION(EXCL)
2228 COPYFILE_OPTION(MOVE)
2229 COPYFILE_OPTION(UNLINK)
2230 COPYFILE_OPTION(PACK)
2231 COPYFILE_OPTION(UNPACK)
2232 COPYFILE_OPTION(CHECK)
2233 COPYFILE_OPTION(VERBOSE)
2234 COPYFILE_OPTION(DEBUG)
2235 {NULL, 0}
2236 };
2237
2238 int main(int c, char *v[])
2239 {
2240 int i;
2241 int flags = 0;
2242
2243 if (c < 3)
2244 errx(1, "insufficient arguments");
2245
2246 while(c-- > 3)
2247 {
2248 for (i = 0; opts[i].s != NULL; ++i)
2249 {
2250 if (strcasecmp(opts[i].s, v[c]) == 0)
2251 {
2252 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
2253 flags |= opts[i].v;
2254 break;
2255 }
2256 }
2257 }
2258
2259 return copyfile(v[1], v[2], NULL, flags);
2260 }
2261 #endif
2262 /*
2263 * Apple Double Create
2264 *
2265 * Create an Apple Double "._" file from a file's extented attributes
2266 *
2267 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2268 */
2269
2270
2271 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2272
2273 #define XATTR_MAXATTRLEN (4*1024)
2274
2275
2276 /*
2277 Typical "._" AppleDouble Header File layout:
2278 ------------------------------------------------------------
2279 MAGIC 0x00051607
2280 VERSION 0x00020000
2281 FILLER 0
2282 COUNT 2
2283 .-- AD ENTRY[0] Finder Info Entry (must be first)
2284 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2285 | '-> FINDER INFO
2286 | ///////////// Fixed Size Data (32 bytes)
2287 | EXT ATTR HDR
2288 | /////////////
2289 | ATTR ENTRY[0] --.
2290 | ATTR ENTRY[1] --+--.
2291 | ATTR ENTRY[2] --+--+--.
2292 | ... | | |
2293 | ATTR ENTRY[N] --+--+--+--.
2294 | ATTR DATA 0 <-' | | |
2295 | //////////// | | |
2296 | ATTR DATA 1 <----' | |
2297 | ///////////// | |
2298 | ATTR DATA 2 <-------' |
2299 | ///////////// |
2300 | ... |
2301 | ATTR DATA N <----------'
2302 | /////////////
2303 | Attribute Free Space
2304 |
2305 '----> RESOURCE FORK
2306 ///////////// Variable Sized Data
2307 /////////////
2308 /////////////
2309 /////////////
2310 /////////////
2311 /////////////
2312 ...
2313 /////////////
2314
2315 ------------------------------------------------------------
2316
2317 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2318 stored as part of the Finder Info. The length in the Finder
2319 Info AppleDouble entry includes the length of the extended
2320 attribute header, attribute entries, and attribute data.
2321 */
2322
2323
2324 /*
2325 * On Disk Data Structures
2326 *
2327 * Note: Motorola 68K alignment and big-endian.
2328 *
2329 * See RFC 1740 for additional information about the AppleDouble file format.
2330 *
2331 */
2332
2333 #define ADH_MAGIC 0x00051607
2334 #define ADH_VERSION 0x00020000
2335 #define ADH_MACOSX "Mac OS X "
2336
2337 /*
2338 * AppleDouble Entry ID's
2339 */
2340 #define AD_DATA 1 /* Data fork */
2341 #define AD_RESOURCE 2 /* Resource fork */
2342 #define AD_REALNAME 3 /* File's name on home file system */
2343 #define AD_COMMENT 4 /* Standard Mac comment */
2344 #define AD_ICONBW 5 /* Mac black & white icon */
2345 #define AD_ICONCOLOR 6 /* Mac color icon */
2346 #define AD_UNUSED 7 /* Not used */
2347 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2348 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2349 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2350 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2351 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2352 #define AD_AFPNAME 13 /* Short name on AFP server */
2353 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2354 #define AD_AFPDIRID 15 /* AFP directory ID */
2355 #define AD_ATTRIBUTES AD_FINDERINFO
2356
2357
2358 #define ATTR_FILE_PREFIX "._"
2359 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2360
2361 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2362
2363 /* Implementation Limits */
2364 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2365 #define ATTR_MAX_NAME_LEN 128
2366 #define ATTR_MAX_HDR_SIZE (65536+18)
2367
2368 /*
2369 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2370 * size supported (including the attribute entries). All of
2371 * the attribute entries must reside within this limit.
2372 */
2373
2374
2375 #define FINDERINFOSIZE 32
2376
2377 typedef struct apple_double_entry
2378 {
2379 u_int32_t type; /* entry type: see list, 0 invalid */
2380 u_int32_t offset; /* entry data offset from the beginning of the file. */
2381 u_int32_t length; /* entry data length in bytes. */
2382 } __attribute__((aligned(2), packed)) apple_double_entry_t;
2383
2384
2385 typedef struct apple_double_header
2386 {
2387 u_int32_t magic; /* == ADH_MAGIC */
2388 u_int32_t version; /* format version: 2 = 0x00020000 */
2389 u_int32_t filler[4];
2390 u_int16_t numEntries; /* number of entries which follow */
2391 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
2392 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
2393 u_int8_t pad[2]; /* get better alignment inside attr_header */
2394 } __attribute__((aligned(2), packed)) apple_double_header_t;
2395
2396
2397 /* Entries are aligned on 4 byte boundaries */
2398 typedef struct attr_entry
2399 {
2400 u_int32_t offset; /* file offset to data */
2401 u_int32_t length; /* size of attribute data */
2402 u_int16_t flags;
2403 u_int8_t namelen; /* length of name including NULL termination char */
2404 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2405 } __attribute__((aligned(2), packed)) attr_entry_t;
2406
2407
2408
2409 /* Header + entries must fit into 64K */
2410 typedef struct attr_header
2411 {
2412 apple_double_header_t appledouble;
2413 u_int32_t magic; /* == ATTR_HDR_MAGIC */
2414 u_int32_t debug_tag; /* for debugging == file id of owning file */
2415 u_int32_t total_size; /* total size of attribute header + entries + data */
2416 u_int32_t data_start; /* file offset to attribute data area */
2417 u_int32_t data_length; /* length of attribute data area */
2418 u_int32_t reserved[3];
2419 u_int16_t flags;
2420 u_int16_t num_attrs;
2421 } __attribute__((aligned(2), packed)) attr_header_t;
2422
2423 /* Empty Resource Fork Header */
2424 /* This comes by way of xnu's vfs_xattr.c */
2425 typedef struct rsrcfork_header {
2426 u_int32_t fh_DataOffset;
2427 u_int32_t fh_MapOffset;
2428 u_int32_t fh_DataLength;
2429 u_int32_t fh_MapLength;
2430 u_int8_t systemData[112];
2431 u_int8_t appData[128];
2432 u_int32_t mh_DataOffset;
2433 u_int32_t mh_MapOffset;
2434 u_int32_t mh_DataLength;
2435 u_int32_t mh_MapLength;
2436 u_int32_t mh_Next;
2437 u_int16_t mh_RefNum;
2438 u_int8_t mh_Attr;
2439 u_int8_t mh_InMemoryAttr;
2440 u_int16_t mh_Types;
2441 u_int16_t mh_Names;
2442 u_int16_t typeCount;
2443 } rsrcfork_header_t;
2444 #define RF_FIRST_RESOURCE 256
2445 #define RF_NULL_MAP_LENGTH 30
2446 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2447
2448 static const rsrcfork_header_t empty_rsrcfork_header = {
2449 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset
2450 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset
2451 0, // fh_DataLength
2452 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength
2453 { RF_EMPTY_TAG, }, // systemData
2454 { 0 }, // appData
2455 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset
2456 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset
2457 0, // mh_DataLength
2458 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength
2459 0, // mh_Next
2460 0, // mh_RefNum
2461 0, // mh_Attr
2462 0, // mh_InMemoryAttr
2463 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types
2464 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names
2465 OSSwapHostToBigInt16(-1), // typeCount
2466 };
2467
2468 #define SWAP16(x) OSSwapBigToHostInt16(x)
2469 #define SWAP32(x) OSSwapBigToHostInt32(x)
2470 #define SWAP64(x) OSSwapBigToHostInt64(x)
2471
2472 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2473
2474 #define ATTR_ENTRY_LENGTH(namelen) \
2475 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2476
2477 #define ATTR_NEXT(ae) \
2478 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2479
2480 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2481
2482 /*
2483 * Endian swap Apple Double header
2484 */
2485 static void
2486 swap_adhdr(apple_double_header_t *adh)
2487 {
2488 #if BYTE_ORDER == LITTLE_ENDIAN
2489 int count;
2490 int i;
2491
2492 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
2493
2494 adh->magic = SWAP32 (adh->magic);
2495 adh->version = SWAP32 (adh->version);
2496 adh->numEntries = SWAP16 (adh->numEntries);
2497
2498 for (i = 0; i < count; i++)
2499 {
2500 adh->entries[i].type = SWAP32 (adh->entries[i].type);
2501 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
2502 adh->entries[i].length = SWAP32 (adh->entries[i].length);
2503 }
2504 #else
2505 (void)adh;
2506 #endif
2507 }
2508
2509 /*
2510 * Endian swap extended attributes header
2511 */
2512 static void
2513 swap_attrhdr(attr_header_t *ah)
2514 {
2515 #if BYTE_ORDER == LITTLE_ENDIAN
2516 attr_entry_t *ae;
2517 int count;
2518 int i;
2519
2520 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
2521
2522 ah->magic = SWAP32 (ah->magic);
2523 ah->debug_tag = SWAP32 (ah->debug_tag);
2524 ah->total_size = SWAP32 (ah->total_size);
2525 ah->data_start = SWAP32 (ah->data_start);
2526 ah->data_length = SWAP32 (ah->data_length);
2527 ah->flags = SWAP16 (ah->flags);
2528 ah->num_attrs = SWAP16 (ah->num_attrs);
2529
2530 ae = (attr_entry_t *)(&ah[1]);
2531 for (i = 0; i < count; i++)
2532 {
2533 attr_entry_t *next = ATTR_NEXT(ae);
2534 ae->offset = SWAP32 (ae->offset);
2535 ae->length = SWAP32 (ae->length);
2536 ae->flags = SWAP16 (ae->flags);
2537 ae = next;
2538 }
2539 #else
2540 (void)ah;
2541 #endif
2542 }
2543
2544 static const u_int32_t emptyfinfo[8] = {0};
2545
2546 /*
2547 * Given an Apple Double file in src, turn it into a
2548 * normal file (possibly with multiple forks, EAs, and
2549 * ACLs) in dst.
2550 */
2551 static int copyfile_unpack(copyfile_state_t s)
2552 {
2553 ssize_t bytes;
2554 void * buffer, * endptr;
2555 apple_double_header_t *adhdr;
2556 ssize_t hdrsize;
2557 int error = 0;
2558
2559 if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
2560 hdrsize = (ssize_t)s->sb.st_size;
2561 else
2562 hdrsize = ATTR_MAX_HDR_SIZE;
2563
2564 buffer = calloc(1, hdrsize);
2565 if (buffer == NULL) {
2566 copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL", hdrsize);
2567 error = -1;
2568 goto exit;
2569 } else
2570 endptr = (char*)buffer + hdrsize;
2571
2572 bytes = pread(s->src_fd, buffer, hdrsize, 0);
2573
2574 if (bytes < 0)
2575 {
2576 copyfile_debug(1, "pread returned: %d", bytes);
2577 error = -1;
2578 goto exit;
2579 }
2580 if (bytes < hdrsize)
2581 {
2582 copyfile_debug(1,
2583 "pread couldn't read entire header: %d of %d",
2584 (int)bytes, (int)s->sb.st_size);
2585 error = -1;
2586 goto exit;
2587 }
2588 adhdr = (apple_double_header_t *)buffer;
2589
2590 /*
2591 * Check for Apple Double file.
2592 */
2593 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
2594 SWAP32(adhdr->magic) != ADH_MAGIC ||
2595 SWAP32(adhdr->version) != ADH_VERSION ||
2596 SWAP16(adhdr->numEntries) != 2 ||
2597 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
2598 {
2599 if (COPYFILE_VERBOSE & s->flags)
2600 copyfile_warn("Not a valid Apple Double header");
2601 error = -1;
2602 goto exit;
2603 }
2604 swap_adhdr(adhdr);
2605
2606 /*
2607 * Remove any extended attributes on the target.
2608 */
2609
2610 if (COPYFILE_XATTR & s->flags)
2611 {
2612 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2613 {
2614 char *namebuf, *name;
2615
2616 if ((namebuf = (char*) malloc(bytes)) == NULL)
2617 {
2618 s->err = ENOMEM;
2619 goto exit;
2620 }
2621 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
2622
2623 if (bytes > 0)
2624 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
2625 (void)fremovexattr(s->dst_fd, name, 0);
2626
2627 free(namebuf);
2628 }
2629 else if (bytes < 0)
2630 {
2631 if (errno != ENOTSUP && errno != EPERM)
2632 goto exit;
2633 }
2634 }
2635
2636 /*
2637 * Extract the extended attributes.
2638 *
2639 * >>> WARNING <<<
2640 * This assumes that the data is already in memory (not
2641 * the case when there are lots of attributes or one of
2642 * the attributes is very large.
2643 */
2644 if (adhdr->entries[0].length > FINDERINFOSIZE)
2645 {
2646 attr_header_t *attrhdr;
2647 attr_entry_t *entry;
2648 int count;
2649 int i;
2650
2651 if ((size_t)hdrsize < sizeof(attr_header_t)) {
2652 copyfile_warn("bad attribute header: %u < %u", hdrsize, sizeof(attr_header_t));
2653 error = -1;
2654 goto exit;
2655 }
2656
2657 attrhdr = (attr_header_t *)buffer;
2658 swap_attrhdr(attrhdr);
2659 if (attrhdr->magic != ATTR_HDR_MAGIC)
2660 {
2661 if (COPYFILE_VERBOSE & s->flags)
2662 copyfile_warn("bad attribute header");
2663 error = -1;
2664 goto exit;
2665 }
2666 count = attrhdr->num_attrs;
2667 entry = (attr_entry_t *)&attrhdr[1];
2668
2669 for (i = 0; i < count; i++)
2670 {
2671 void * dataptr;
2672
2673 /*
2674 * First we do some simple sanity checking.
2675 * +) See if entry is within the buffer's range;
2676 *
2677 * +) Check the attribute name length; if it's longer than the
2678 * maximum, we truncate it down. (We could error out as well;
2679 * I'm not sure which is the better way to go here.)
2680 *
2681 * +) If, given the name length, it goes beyond the end of
2682 * the buffer, error out.
2683 *
2684 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2685 * truncated the name length above, we truncate the name here.)
2686 *
2687 * +) If entry->offset is so large that it causes dataptr to
2688 * go beyond the end of the buffer -- or, worse, so large that
2689 * it wraps around! -- we error out.
2690 *
2691 * +) If entry->length would cause the entry to go beyond the
2692 * end of the buffer (or, worse, wrap around to before it),
2693 * *or* if the length is larger than the hdrsize, we error out.
2694 * (An explanation of that: what we're checking for there is
2695 * the small range of values such that offset+length would cause
2696 * it to go beyond endptr, and then wrap around past buffer. We
2697 * care about this because we are passing entry->length down to
2698 * fgetxattr() below, and an erroneously large value could cause
2699 * problems there. By making sure that it's less than hdrsize,
2700 * which has already been sanity-checked above, we're safe.
2701 * That may mean that the check against < buffer is unnecessary.)
2702 */
2703 if ((void*)entry >= endptr || (void*)entry < buffer) {
2704 if (COPYFILE_VERBOSE & s->flags)
2705 copyfile_warn("Incomplete or corrupt attribute entry");
2706 error = -1;
2707 s->err = EINVAL;
2708 goto exit;
2709 }
2710
2711 if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
2712 if (COPYFILE_VERBOSE & s->flags)
2713 copyfile_warn("Incomplete or corrupt attribute entry");
2714 error = -1;
2715 s->err = EINVAL;
2716 goto exit;
2717 }
2718
2719 if (entry->namelen < 2) {
2720 if (COPYFILE_VERBOSE & s->flags)
2721 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
2722 error = -1;
2723 s->err = EINVAL;
2724 goto exit;
2725 }
2726
2727 if (entry->namelen > XATTR_MAXNAMELEN + 1) {
2728 if (COPYFILE_VERBOSE & s->flags)
2729 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
2730 error = -1;
2731 s->err = EINVAL;
2732 goto exit;
2733 }
2734
2735 if ((void*)(entry->name + entry->namelen) > endptr) {
2736 if (COPYFILE_VERBOSE & s->flags)
2737 copyfile_warn("Incomplete or corrupt attribute entry");
2738 error = -1;
2739 s->err = EINVAL;
2740 goto exit;
2741 }
2742
2743 /* Because namelen includes the NUL, we check one byte back */
2744 if (entry->name[entry->namelen-1] != 0) {
2745 if (COPYFILE_VERBOSE & s->flags)
2746 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
2747 error = -1;
2748 s->err = EINVAL;
2749 goto exit;
2750 }
2751
2752 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
2753 entry->name, entry->length, entry->offset);
2754
2755 dataptr = (char *)attrhdr + entry->offset;
2756
2757 if (dataptr > endptr || dataptr < buffer) {
2758 copyfile_debug(1, "Entry %d overflows: offset = %u", entry->offset);
2759 error = -1;
2760 s->err = EINVAL; /* Invalid buffer */
2761 goto exit;
2762 }
2763 if (((char*)dataptr + entry->length) > (char*)endptr ||
2764 (((char*)dataptr + entry->length) < (char*)buffer) ||
2765 (entry->length > (size_t)hdrsize)) {
2766 if (COPYFILE_VERBOSE & s->flags)
2767 copyfile_warn("Incomplete or corrupt attribute entry");
2768 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
2769 entry->offset, entry->length);
2770 error = -1;
2771 s->err = EINVAL; /* Invalid buffer */
2772 goto exit;
2773 }
2774
2775 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
2776 {
2777 qtn_file_t tqinfo = NULL;
2778
2779 if (s->qinfo == NULL)
2780 {
2781 tqinfo = qtn_file_alloc();
2782 if (tqinfo)
2783 {
2784 int x;
2785 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
2786 {
2787 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
2788 qtn_file_free(tqinfo);
2789 tqinfo = NULL;
2790 }
2791 }
2792 }
2793 else
2794 {
2795 tqinfo = s->qinfo;
2796 }
2797 if (tqinfo)
2798 {
2799 int x;
2800 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
2801 if (x != 0)
2802 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
2803 }
2804 if (tqinfo && !s->qinfo)
2805 {
2806 qtn_file_free(tqinfo);
2807 }
2808 }
2809 /* Look for ACL data */
2810 else if (COPYFILE_ACL & s->flags && strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
2811 {
2812 acl_t acl;
2813 struct stat sb;
2814 int retry = 1;
2815 char *tcp = dataptr;
2816
2817 /*
2818 * acl_from_text() requires a NUL-terminated string. The ACL EA,
2819 * however, may not be NUL-terminated. So in that case, we need to
2820 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
2821 */
2822 if (tcp[entry->length - 1] != 0) {
2823 char *tmpstr = malloc(entry->length + 1);
2824 if (tmpstr == NULL) {
2825 error = -1;
2826 goto exit;
2827 }
2828 strlcpy(tmpstr, tcp, entry->length + 1);
2829 acl = acl_from_text(tmpstr);
2830 free(tmpstr);
2831 } else {
2832 acl = acl_from_text(tcp);
2833 }
2834
2835 if (acl != NULL)
2836 {
2837 filesec_t fsec_tmp;
2838
2839 if ((fsec_tmp = filesec_init()) == NULL)
2840 error = -1;
2841 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
2842 error = -1;
2843 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
2844 error = -1;
2845 else {
2846 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
2847 {
2848 if (errno == ENOTSUP)
2849 {
2850 if (retry && !copyfile_unset_acl(s))
2851 {
2852 retry = 0;
2853 continue;
2854 }
2855 }
2856 copyfile_warn("setting security information");
2857 error = -1;
2858 break;
2859 }
2860 }
2861 acl_free(acl);
2862 filesec_free(fsec_tmp);
2863
2864 if (error == -1)
2865 goto exit;
2866 }
2867 }
2868 /* And, finally, everything else */
2869 else if (COPYFILE_XATTR & s->flags) {
2870 if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
2871 if (COPYFILE_VERBOSE & s->flags)
2872 copyfile_warn("error %d setting attribute %s", error, entry->name);
2873 error = -1;
2874 goto exit;
2875 }
2876 }
2877 entry = ATTR_NEXT(entry);
2878 }
2879 }
2880
2881 /*
2882 * Extract the Finder Info.
2883 */
2884 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
2885 error = -1;
2886 goto exit;
2887 }
2888
2889 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
2890 {
2891 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
2892 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
2893 if (error)
2894 goto exit;
2895 }
2896
2897 /*
2898 * Extract the Resource Fork.
2899 */
2900 if (adhdr->entries[1].type == AD_RESOURCE &&
2901 adhdr->entries[1].length > 0)
2902 {
2903 void * rsrcforkdata = NULL;
2904 size_t length;
2905 off_t offset;
2906 struct stat sb;
2907 struct timeval tval[2];
2908
2909 length = adhdr->entries[1].length;
2910 offset = adhdr->entries[1].offset;
2911 rsrcforkdata = malloc(length);
2912
2913 if (rsrcforkdata == NULL) {
2914 copyfile_debug(1, "could not allocate %u bytes for rsrcforkdata",
2915 length);
2916 error = -1;
2917 goto bad;
2918 }
2919
2920 if (fstat(s->dst_fd, &sb) < 0)
2921 {
2922 copyfile_debug(1, "couldn't stat destination file");
2923 error = -1;
2924 goto bad;
2925 }
2926
2927 bytes = pread(s->src_fd, rsrcforkdata, length, offset);
2928 if (bytes < (ssize_t)length)
2929 {
2930 if (bytes == -1)
2931 {
2932 copyfile_debug(1, "couldn't read resource fork");
2933 }
2934 else
2935 {
2936 copyfile_debug(1,
2937 "couldn't read resource fork (only read %d bytes of %d)",
2938 (int)bytes, (int)length);
2939 }
2940 error = -1;
2941 goto bad;
2942 }
2943 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
2944 if (error)
2945 {
2946 /*
2947 * For filesystems that do not natively support named attributes,
2948 * the kernel creates an AppleDouble file that -- for compatabilty
2949 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
2950 * structure that says there are no resources. So, if fsetxattr has
2951 * failed, and the resource fork is that empty structure, *and* the
2952 * target file is a directory, then we do nothing with it.
2953 */
2954 if ((bytes == sizeof(rsrcfork_header_t)) &&
2955 ((sb.st_mode & S_IFMT) == S_IFDIR) &&
2956 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
2957 copyfile_debug(2, "not setting empty resource fork on directory");
2958 error = errno = 0;
2959 goto bad;
2960 }
2961 copyfile_debug(1, "error %d setting resource fork attribute", error);
2962 error = -1;
2963 goto bad;
2964 }
2965 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
2966 XATTR_RESOURCEFORK_NAME, (int)length);
2967
2968 if (!(s->flags & COPYFILE_STAT))
2969 {
2970 tval[0].tv_sec = sb.st_atime;
2971 tval[1].tv_sec = sb.st_mtime;
2972 tval[0].tv_usec = tval[1].tv_usec = 0;
2973
2974 if (futimes(s->dst_fd, tval))
2975 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
2976 }
2977 bad:
2978 if (rsrcforkdata)
2979 free(rsrcforkdata);
2980 }
2981
2982 if (COPYFILE_STAT & s->flags)
2983 {
2984 error = copyfile_stat(s);
2985 }
2986 exit:
2987 if (buffer) free(buffer);
2988 return error;
2989 }
2990
2991 static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
2992 {
2993 int ret = 0;
2994 char qbuf[QTN_SERIALIZED_DATA_MAX];
2995 size_t qlen = sizeof(qbuf);
2996
2997 if (s->qinfo == NULL)
2998 {
2999 ret = -1;
3000 goto done;
3001 }
3002
3003 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
3004 {
3005 ret = -1;
3006 goto done;
3007 }
3008
3009 *buf = malloc(qlen);
3010 if (*buf)
3011 {
3012 memcpy(*buf, qbuf, qlen);
3013 *len = qlen;
3014 }
3015 done:
3016 return ret;
3017 }
3018
3019 static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
3020 {
3021 int ret = 0;
3022 acl_t acl = NULL;
3023 char *acl_text;
3024
3025 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
3026 {
3027 if (errno != ENOENT)
3028 {
3029 ret = -1;
3030 if (COPYFILE_VERBOSE & s->flags)
3031 copyfile_warn("getting acl");
3032 }
3033 *len = 0;
3034 goto exit;
3035 }
3036
3037 if ((acl_text = acl_to_text(acl, len)) != NULL)
3038 {
3039 /*
3040 * acl_to_text() doesn't include the NUL at the endo
3041 * in it's count (*len). It does, however, promise to
3042 * return a valid C string, so we need to up the count
3043 * by 1.
3044 */
3045 *len = *len + 1;
3046 *buf = malloc(*len);
3047 if (*buf)
3048 memcpy(*buf, acl_text, *len);
3049 else
3050 *len = 0;
3051 acl_free(acl_text);
3052 }
3053 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
3054 exit:
3055 if (acl)
3056 acl_free(acl);
3057 return ret;
3058 }
3059
3060 static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
3061 {
3062 ssize_t datasize;
3063 char *databuf = NULL;
3064 int ret = 0;
3065
3066 /* Get the resource fork size */
3067 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
3068 {
3069 if (COPYFILE_VERBOSE & s->flags)
3070 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
3071 return -1;
3072 }
3073
3074 if (datasize > INT_MAX) {
3075 s->err = EINVAL;
3076 ret = -1;
3077 goto done;
3078 }
3079
3080 if ((databuf = malloc(datasize)) == NULL)
3081 {
3082 copyfile_warn("malloc");
3083 ret = -1;
3084 goto done;
3085 }
3086
3087 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
3088 {
3089 if (COPYFILE_VERBOSE & s->flags)
3090 copyfile_warn("couldn't read entire resource fork");
3091 ret = -1;
3092 goto done;
3093 }
3094
3095 /* Write the resource fork to disk. */
3096 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
3097 {
3098 if (COPYFILE_VERBOSE & s->flags)
3099 copyfile_warn("couldn't write resource fork");
3100 }
3101 copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
3102 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
3103 filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
3104
3105 done:
3106 if (databuf)
3107 free(databuf);
3108
3109 return ret;
3110 }
3111
3112 /*
3113 * The opposite of copyfile_unpack(), obviously.
3114 */
3115 static int copyfile_pack(copyfile_state_t s)
3116 {
3117 char *attrnamebuf = NULL, *endnamebuf;
3118 void *databuf = NULL;
3119 attr_header_t *filehdr, *endfilehdr;
3120 attr_entry_t *entry;
3121 ssize_t listsize = 0;
3122 char *nameptr;
3123 size_t namelen;
3124 size_t entrylen;
3125 ssize_t datasize;
3126 size_t offset = 0;
3127 int hasrsrcfork = 0;
3128 int error = 0;
3129 int seenq = 0; // Have we seen any quarantine info already?
3130
3131 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
3132 if (filehdr == NULL) {
3133 error = -1;
3134 goto exit;
3135 } else {
3136 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
3137 }
3138
3139 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
3140 if (attrnamebuf == NULL) {
3141 error = -1;
3142 goto exit;
3143 } else {
3144 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
3145 }
3146
3147 /*
3148 * Fill in the Apple Double Header defaults.
3149 */
3150 filehdr->appledouble.magic = ADH_MAGIC;
3151 filehdr->appledouble.version = ADH_VERSION;
3152 filehdr->appledouble.numEntries = 2;
3153 filehdr->appledouble.entries[0].type = AD_FINDERINFO;
3154 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo);
3155 filehdr->appledouble.entries[0].length = FINDERINFOSIZE;
3156 filehdr->appledouble.entries[1].type = AD_RESOURCE;
3157 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad);
3158 filehdr->appledouble.entries[1].length = 0;
3159 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
3160
3161 /*
3162 * Fill in the initial Attribute Header.
3163 */
3164 filehdr->magic = ATTR_HDR_MAGIC;
3165 filehdr->debug_tag = (u_int32_t)s->sb.st_ino;
3166 filehdr->data_start = (u_int32_t)sizeof(attr_header_t);
3167
3168 /*
3169 * Collect the attribute names.
3170 */
3171 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3172
3173 /*
3174 * Test if there are acls to copy
3175 */
3176 if (COPYFILE_ACL & s->flags)
3177 {
3178 acl_t temp_acl = NULL;
3179 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
3180 {
3181 copyfile_debug(2, "no acl entries found (errno = %d)", errno);
3182 } else
3183 {
3184 offset = strlen(XATTR_SECURITY_NAME) + 1;
3185 strcpy(attrnamebuf, XATTR_SECURITY_NAME);
3186 }
3187 if (temp_acl)
3188 acl_free(temp_acl);
3189 }
3190
3191 if (COPYFILE_XATTR & s->flags)
3192 {
3193 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3194 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
3195 {
3196 copyfile_debug(2, "no extended attributes found (%d)", errno);
3197 }
3198 if (listsize > left)
3199 {
3200 copyfile_debug(1, "extended attribute list too long");
3201 listsize = left;
3202 }
3203
3204 listsize += offset;
3205 endnamebuf = attrnamebuf + listsize;
3206 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
3207 error = -1;
3208 goto exit;
3209 }
3210
3211 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
3212 {
3213 namelen = strlen(nameptr) + 1;
3214 /* Skip over FinderInfo or Resource Fork names */
3215 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
3216 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
3217 continue;
3218 }
3219 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
3220 seenq = 1;
3221 }
3222
3223 /* The system should prevent this from happening, but... */
3224 if (namelen > XATTR_MAXNAMELEN + 1) {
3225 namelen = XATTR_MAXNAMELEN + 1;
3226 }
3227 entry->namelen = namelen;
3228 entry->flags = 0;
3229 if (nameptr + namelen > endnamebuf) {
3230 error = -1;
3231 goto exit;
3232 }
3233 bcopy(nameptr, &entry->name[0], namelen);
3234 copyfile_debug(2, "copied name [%s]", entry->name);
3235
3236 entrylen = ATTR_ENTRY_LENGTH(namelen);
3237 entry = (attr_entry_t *)(((char *)entry) + entrylen);
3238
3239 if ((void*)entry >= (void*)endfilehdr) {
3240 error = -1;
3241 goto exit;
3242 }
3243
3244 /* Update the attributes header. */
3245 filehdr->num_attrs++;
3246 filehdr->data_start += (u_int32_t)entrylen;
3247 }
3248 }
3249
3250 /*
3251 * If we have any quarantine data, we always pack it.
3252 * But if we've already got it in the EA list, don't put it in again.
3253 */
3254 if (s->qinfo && !seenq)
3255 {
3256 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3257 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3258 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
3259 }
3260
3261 seenq = 0;
3262 /*
3263 * Collect the attribute data.
3264 */
3265 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3266
3267 for (nameptr = attrnamebuf; nameptr < attrnamebuf + listsize; nameptr += namelen + 1)
3268 {
3269 namelen = strlen(nameptr);
3270
3271 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
3272 copyfile_pack_acl(s, &databuf, &datasize);
3273 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
3274 {
3275 copyfile_pack_quarantine(s, &databuf, &datasize);
3276 }
3277 /* Check for Finder Info. */
3278 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
3279 {
3280 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
3281 if (datasize < 0)
3282 {
3283 if (COPYFILE_VERBOSE & s->flags)
3284 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3285 } else if (datasize != 32)
3286 {
3287 if (COPYFILE_VERBOSE & s->flags)
3288 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
3289 } else
3290 {
3291 if (COPYFILE_VERBOSE & s->flags)
3292 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3293 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
3294 }
3295 continue; /* finder info doesn't have an attribute entry */
3296 }
3297 /* Check for Resource Fork. */
3298 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
3299 {
3300 hasrsrcfork = 1;
3301 continue;
3302 } else
3303 {
3304 /* Just a normal attribute. */
3305 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
3306 if (datasize == 0)
3307 goto next;
3308 if (datasize < 0)
3309 {
3310 if (COPYFILE_VERBOSE & s->flags)
3311 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3312 goto next;
3313 }
3314 if (datasize > XATTR_MAXATTRLEN)
3315 {
3316 if (COPYFILE_VERBOSE & s->flags)
3317 copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
3318 goto next;
3319 }
3320 databuf = malloc(datasize);
3321 if (databuf == NULL) {
3322 error = -1;
3323 continue;
3324 }
3325 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
3326 }
3327
3328 entry->length = (u_int32_t)datasize;
3329 entry->offset = filehdr->data_start + filehdr->data_length;
3330
3331 filehdr->data_length += (u_int32_t)datasize;
3332 /*
3333 * >>> WARNING <<<
3334 * This assumes that the data is fits in memory (not
3335 * the case when there are lots of attributes or one of
3336 * the attributes is very large.
3337 */
3338 if (entry->offset > ATTR_MAX_SIZE ||
3339 (entry->offset + datasize > ATTR_MAX_SIZE)) {
3340 error = 1;
3341 } else {
3342 bcopy(databuf, (char*)filehdr + entry->offset, datasize);
3343 }
3344 free(databuf);
3345
3346 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
3347 next:
3348 /* bump to next entry */
3349 entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
3350 entry = (attr_entry_t *)((char *)entry + entrylen);
3351 }
3352
3353 if (filehdr->data_length > 0)
3354 {
3355 /* Now we know where the resource fork data starts. */
3356 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
3357
3358 /* We also know the size of the "Finder Info entry. */
3359 filehdr->appledouble.entries[0].length =
3360 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
3361
3362 filehdr->total_size = filehdr->appledouble.entries[1].offset;
3363 }
3364
3365 /* Copy Resource Fork. */
3366 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
3367 goto exit;
3368
3369 /* Write the header to disk. */
3370 datasize = filehdr->appledouble.entries[1].offset;
3371
3372 swap_adhdr(&filehdr->appledouble);
3373 swap_attrhdr(filehdr);
3374
3375 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
3376 {
3377 if (COPYFILE_VERBOSE & s->flags)
3378 copyfile_warn("couldn't write file header");
3379 error = -1;
3380 goto exit;
3381 }
3382 exit:
3383 if (filehdr) free(filehdr);
3384 if (attrnamebuf) free(attrnamebuf);
3385
3386 if (error)
3387 return error;
3388 else
3389 return copyfile_stat(s);
3390 }