]> git.saurik.com Git - apple/copyfile.git/blob - copyfile.c
copyfile-66.1.tar.gz
[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 && !(s->flags & COPYFILE_UNPACK))
1484 break;
1485 oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY;
1486 continue;
1487 }
1488 copyfile_warn("open on %s", s->dst);
1489 return -1;
1490 }
1491 copyfile_debug(2, "open successful on destination (%s)", s->dst);
1492 }
1493
1494 if (s->dst_fd < 0 || s->src_fd < 0)
1495 {
1496 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1497 s->src_fd, s->dst_fd);
1498 s->err = EINVAL;
1499 return -1;
1500 }
1501 return 0;
1502 }
1503
1504
1505 /*
1506 * copyfile_check(), as described above, essentially tells you
1507 * what you'd have to copy, if you wanted it to copy the things
1508 * you asked it to copy.
1509 * In other words, if you pass in COPYFILE_ALL, and the file in
1510 * question had no extended attributes but did have an ACL, you'd
1511 * get back COPYFILE_ACL.
1512 */
1513 static copyfile_flags_t copyfile_check(copyfile_state_t s)
1514 {
1515 acl_t acl = NULL;
1516 copyfile_flags_t ret = 0;
1517 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
1518 qtn_file_t qinfo;
1519
1520 if (!s->src)
1521 {
1522 s->err = EINVAL;
1523 return -1;
1524 }
1525
1526 /* check EAs */
1527 if (COPYFILE_XATTR & s->flags)
1528 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
1529 {
1530 ret |= COPYFILE_XATTR;
1531 }
1532
1533 if (COPYFILE_ACL & s->flags)
1534 {
1535 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1536 (s->src, &s->sb, s->fsec);
1537
1538 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
1539 ret |= COPYFILE_ACL;
1540 }
1541
1542 copyfile_debug(2, "check result: %d (%s)", ret, s->src);
1543
1544 if (acl)
1545 acl_free(acl);
1546
1547 if (s->qinfo) {
1548 /* If the state has had quarantine info set already, we use that */
1549 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1550 } else {
1551 qinfo = qtn_file_alloc();
1552 /*
1553 * For quarantine information, we need to see if the source file
1554 * has any. Since it may be a symlink, however, and we may, or
1555 * not be following, *and* there's no qtn* routine which can optionally
1556 * follow or not follow a symlink, we need to instead work around
1557 * this limitation.
1558 */
1559 if (qinfo) {
1560 int fd;
1561 int qret = 0;
1562 struct stat sbuf;
1563
1564 /*
1565 * If we care about not following symlinks, *and* the file exists
1566 * (which is to say, lstat doesn't return an error), *and* the file
1567 * is a symlink, then we open it up (with O_SYMLINK), and use
1568 * qtn_file_init_with_fd(); if none of that is true, however, then
1569 * we can simply use qtn_file_init_with_path().
1570 */
1571 if (nofollow
1572 && lstat(s->src, &sbuf) == 0
1573 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
1574 fd = open(s->src, O_RDONLY | O_SYMLINK);
1575 if (fd != -1) {
1576 if (!qtn_file_init_with_fd(qinfo, fd)) {
1577 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1578 }
1579 close(fd);
1580 }
1581 } else {
1582 if (!qtn_file_init_with_path(qinfo, s->src)) {
1583 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1584 }
1585 }
1586 qtn_file_free(qinfo);
1587 ret |= qret;
1588 }
1589 }
1590 return ret;
1591 }
1592
1593 /*
1594 * Attempt to copy the data section of a file. Using blockisize
1595 * is not necessarily the fastest -- it might be desirable to
1596 * specify a blocksize, somehow. But it's a size that should be
1597 * guaranteed to work.
1598 */
1599 static int copyfile_data(copyfile_state_t s)
1600 {
1601 size_t blen;
1602 char *bp = 0;
1603 ssize_t nread;
1604 int ret = 0;
1605 size_t iBlocksize = 0;
1606 size_t oBlocksize = 0;
1607 const size_t onegig = 1 << 30;
1608 struct statfs sfs;
1609 copyfile_callback_t status = s->statuscb;
1610
1611 /* Unless it's a normal file, we don't copy. For now, anyway */
1612 if ((s->sb.st_mode & S_IFMT) != S_IFREG)
1613 return 0;
1614
1615 if (fstatfs(s->src_fd, &sfs) == -1) {
1616 iBlocksize = s->sb.st_blksize;
1617 } else {
1618 iBlocksize = sfs.f_iosize;
1619 }
1620
1621 /* Work-around for 6453525, limit blocksize to 1G */
1622 if (iBlocksize > onegig) {
1623 iBlocksize = onegig;
1624 }
1625
1626 if ((bp = malloc(iBlocksize)) == NULL)
1627 return -1;
1628
1629 if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) {
1630 oBlocksize = iBlocksize;
1631 } else {
1632 oBlocksize = sfs.f_iosize;
1633 if (oBlocksize > onegig)
1634 oBlocksize = onegig;
1635 }
1636
1637 blen = iBlocksize;
1638
1639 s->totalCopied = 0;
1640 /* If supported, do preallocation for Xsan / HFS volumes */
1641 #ifdef F_PREALLOCATE
1642 {
1643 fstore_t fst;
1644
1645 fst.fst_flags = 0;
1646 fst.fst_posmode = F_PEOFPOSMODE;
1647 fst.fst_offset = 0;
1648 fst.fst_length = s->sb.st_size;
1649 /* Ignore errors; this is merely advisory. */
1650 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
1651 }
1652 #endif
1653
1654 while ((nread = read(s->src_fd, bp, blen)) > 0)
1655 {
1656 ssize_t nwritten;
1657 size_t left = nread;
1658 void *ptr = bp;
1659 int loop = 0;
1660
1661 while (left > 0) {
1662 nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize));
1663 switch (nwritten) {
1664 case 0:
1665 if (++loop > 5) {
1666 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
1667 ret = -1;
1668 s->err = EAGAIN;
1669 goto exit;
1670 }
1671 break;
1672 case -1:
1673 copyfile_warn("writing to output file got error");
1674 if (status) {
1675 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1676 if (rv == COPYFILE_SKIP) { // Skip the data copy
1677 ret = 0;
1678 goto exit;
1679 }
1680 if (rv == COPYFILE_CONTINUE) { // Retry the write
1681 errno = 0;
1682 continue;
1683 }
1684 }
1685 ret = -1;
1686 goto exit;
1687 default:
1688 left -= nwritten;
1689 ptr = ((char*)ptr) + nwritten;
1690 loop = 0;
1691 break;
1692 }
1693 s->totalCopied += nwritten;
1694 if (status) {
1695 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
1696 if (rv == COPYFILE_QUIT) {
1697 ret = -1; s->err = ECANCELED;
1698 goto exit;
1699 }
1700 }
1701 }
1702 }
1703 if (nread < 0)
1704 {
1705 copyfile_warn("reading from %s", s->src ? s->src : "(null src)");
1706 ret = -1;
1707 goto exit;
1708 }
1709
1710 if (ftruncate(s->dst_fd, s->sb.st_size) < 0)
1711 {
1712 ret = -1;
1713 goto exit;
1714 }
1715
1716 exit:
1717 if (ret == -1)
1718 {
1719 s->err = errno;
1720 }
1721 free(bp);
1722 return ret;
1723 }
1724
1725 /*
1726 * copyfile_security() will copy the ACL set, and the
1727 * POSIX set. Complexities come when dealing with
1728 * inheritied permissions, and when dealing with both
1729 * POSIX and ACL permissions.
1730 */
1731 static int copyfile_security(copyfile_state_t s)
1732 {
1733 int copied = 0;
1734 int has_uberace = 0;
1735 acl_flagset_t flags;
1736 struct stat sb;
1737 acl_entry_t entry_src = NULL, entry_dst = NULL;
1738 acl_t acl_src = NULL, acl_dst = NULL;
1739 int ret = 0;
1740 filesec_t tmp_fsec = NULL;
1741 filesec_t fsec_dst = filesec_init();
1742
1743 if (fsec_dst == NULL)
1744 return -1;
1745
1746
1747 if (COPYFILE_ACL & s->flags)
1748 {
1749 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
1750 {
1751 if (errno == ENOENT)
1752 acl_src = NULL;
1753 else
1754 goto error_exit;
1755 }
1756
1757 /* grab the destination acl
1758 cannot assume it's empty due to inheritance
1759 */
1760 if(fstatx_np(s->dst_fd, &sb, fsec_dst))
1761 goto error_exit;
1762
1763 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
1764 {
1765 if (errno == ENOENT)
1766 acl_dst = NULL;
1767 else
1768 goto error_exit;
1769 }
1770 else
1771 {
1772 acl_t tmp = acl_init(4);
1773 acl_entry_t ace = NULL;
1774 int count = 0;
1775
1776 if (tmp == NULL)
1777 goto error_exit;
1778
1779
1780 for (; acl_get_entry(acl_dst,
1781 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1782 &ace) == 0;)
1783 {
1784 if (count++ == 0 && is_uberace(ace)) {
1785 if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
1786 break;
1787 if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
1788 break;
1789 has_uberace = 1;
1790 continue;
1791 }
1792 acl_get_flagset_np(ace, &flags);
1793 if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1794 {
1795 if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
1796 break;
1797 if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
1798 break;
1799 }
1800 }
1801 acl_free(acl_dst);
1802 acl_dst = tmp;
1803
1804 if (ret == -1)
1805 goto error_exit;
1806 }
1807
1808 if (acl_src == NULL && acl_dst == NULL)
1809 goto no_acl;
1810
1811 if (acl_src) {
1812 if (acl_dst == NULL)
1813 acl_dst = acl_init(4);
1814 for (copied = 0;acl_get_entry(acl_src,
1815 entry_src == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1816 &entry_src) == 0;)
1817 {
1818 acl_get_flagset_np(entry_src, &flags);
1819 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1820 {
1821 if ((ret = acl_create_entry(&acl_dst, &entry_dst)) == -1)
1822 goto error_exit;
1823
1824 if ((ret = acl_copy_entry(entry_dst, entry_src)) == -1)
1825 goto error_exit;
1826
1827 copyfile_debug(2, "copied acl entry from %s to %s",
1828 s->src ? s->src : "(null src)",
1829 s->dst ? s->dst : "(null dst)");
1830 copied++;
1831 }
1832 }
1833 }
1834 if (!has_uberace && (s->internal_flags & cfDelayAce)) {
1835 if (add_uberace(&acl_dst))
1836 goto error_exit;
1837 }
1838 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_dst))
1839 {
1840 copyfile_debug(3, "altered acl");
1841 }
1842 }
1843 no_acl:
1844 /*
1845 * The following code is attempting to ensure that only the requested
1846 * security information gets copied over to the destination file.
1847 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
1848 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
1849 * this function).
1850 *
1851 * If we have both flags, we copy everything; if we have ACL but not STAT,
1852 * we remove the POSIX information from the filesec object, and apply the
1853 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
1854 * the extended version.
1855 */
1856 tmp_fsec = filesec_dup(s->fsec);
1857 if (tmp_fsec == NULL) {
1858 goto error_exit;
1859 }
1860
1861 switch (COPYFILE_SECURITY & s->flags) {
1862 case COPYFILE_ACL:
1863 copyfile_unset_posix_fsec(tmp_fsec);
1864 /* FALLTHROUGH */
1865 case COPYFILE_ACL | COPYFILE_STAT:
1866 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
1867 acl_t acl = NULL;
1868 /*
1869 * The call could have failed for a number of reasons, since
1870 * it does a number of things: it changes the mode of the file,
1871 * sets the owner and group, and applies an ACL (if one exists).
1872 * The typical failure is going to be trying to set the group of
1873 * the destination file to match the source file, when the process
1874 * doesn't have permission to put files in that group. We try to
1875 * work around this by breaking the steps out and doing them
1876 * discretely. We don't care if the fchown fails, but we do care
1877 * if the mode or ACL can't be set. For historical reasons, we
1878 * simply log those failures, however.
1879 */
1880
1881 #define NS(x) ((x) ? (x) : "(null string)")
1882 if (fchmod(s->dst_fd, s->sb.st_mode) == -1) {
1883 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src));
1884 }
1885 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
1886 if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) {
1887 if (acl_set_fd(s->dst_fd, acl) == -1) {
1888 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src));
1889 }
1890 acl_free(acl);
1891 }
1892 }
1893 #undef NS
1894 break;
1895 case COPYFILE_STAT:
1896 (void)fchmod(s->dst_fd, s->sb.st_mode);
1897 break;
1898 }
1899 filesec_free(tmp_fsec);
1900 exit:
1901 filesec_free(fsec_dst);
1902 if (acl_src) acl_free(acl_src);
1903 if (acl_dst) acl_free(acl_dst);
1904
1905 return ret;
1906
1907 error_exit:
1908 ret = -1;
1909 goto exit;
1910
1911 }
1912
1913 /*
1914 * Attempt to set the destination file's stat information -- including
1915 * flags and time-related fields -- to the source's.
1916 */
1917 static int copyfile_stat(copyfile_state_t s)
1918 {
1919 struct timeval tval[2];
1920 /*
1921 * NFS doesn't support chflags; ignore errors unless there's reason
1922 * to believe we're losing bits. (Note, this still won't be right
1923 * if the server supports flags and we were trying to *remove* flags
1924 * on a file that we copied, i.e., that we didn't create.)
1925 */
1926 if (fchflags(s->dst_fd, (u_int)s->sb.st_flags))
1927 if (errno != EOPNOTSUPP || s->sb.st_flags != 0)
1928 copyfile_warn("%s: set flags (was: 0%07o)", s->dst ? s->dst : "(null dst)", s->sb.st_flags);
1929
1930 /* If this fails, we don't care */
1931 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
1932
1933 /* This may have already been done in copyfile_security() */
1934 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
1935
1936 tval[0].tv_sec = s->sb.st_atime;
1937 tval[1].tv_sec = s->sb.st_mtime;
1938 tval[0].tv_usec = tval[1].tv_usec = 0;
1939 if (futimes(s->dst_fd, tval))
1940 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
1941 return 0;
1942 }
1943
1944 /*
1945 * Similar to copyfile_security() in some ways; this
1946 * routine copies the extended attributes from the source,
1947 * and sets them on the destination.
1948 * The procedure is pretty simple, even if it is verbose:
1949 * for each named attribute on the destination, get its name, and
1950 * remove it. We should have none after that.
1951 * For each named attribute on the source, get its name, get its
1952 * data, and set it on the destination.
1953 */
1954 static int copyfile_xattr(copyfile_state_t s)
1955 {
1956 char *name;
1957 char *namebuf, *end;
1958 ssize_t xa_size;
1959 void *xa_dataptr;
1960 ssize_t bufsize = 4096;
1961 ssize_t asize;
1962 ssize_t nsize;
1963 int ret = 0;
1964
1965 /* delete EAs on destination */
1966 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
1967 {
1968 if ((namebuf = (char *) malloc(nsize)) == NULL)
1969 return -1;
1970 else
1971 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
1972
1973 if (nsize > 0) {
1974 /*
1975 * With this, end points to the last byte of the allocated buffer
1976 * This *should* be NUL, from flistxattr, but if it's not, we can
1977 * set it anyway -- it'll result in a truncated name, which then
1978 * shouldn't match when we get them later.
1979 */
1980 end = namebuf + nsize - 1;
1981 if (*end != 0)
1982 *end = 0;
1983 for (name = namebuf; name <= end; name += strlen(name) + 1) {
1984 /* If the quarantine information shows up as an EA, we skip over it */
1985 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
1986 continue;
1987 }
1988 fremovexattr(s->dst_fd, name,0);
1989 }
1990 }
1991 free(namebuf);
1992 } else
1993 if (nsize < 0)
1994 {
1995 if (errno == ENOTSUP || errno == EPERM)
1996 return 0;
1997 else
1998 return -1;
1999 }
2000
2001 /* get name list of EAs on source */
2002 if ((nsize = flistxattr(s->src_fd, 0, 0, 0)) < 0)
2003 {
2004 if (errno == ENOTSUP || errno == EPERM)
2005 return 0;
2006 else
2007 return -1;
2008 } else
2009 if (nsize == 0)
2010 return 0;
2011
2012 if ((namebuf = (char *) malloc(nsize)) == NULL)
2013 return -1;
2014 else
2015 nsize = flistxattr(s->src_fd, namebuf, nsize, 0);
2016
2017 if (nsize <= 0) {
2018 free(namebuf);
2019 return (int)nsize;
2020 }
2021
2022 /*
2023 * With this, end points to the last byte of the allocated buffer
2024 * This *should* be NUL, from flistxattr, but if it's not, we can
2025 * set it anyway -- it'll result in a truncated name, which then
2026 * shouldn't match when we get them later.
2027 */
2028 end = namebuf + nsize - 1;
2029 if (*end != 0)
2030 *end = 0;
2031
2032 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
2033 free(namebuf);
2034 return -1;
2035 }
2036
2037 for (name = namebuf; name <= end; name += strlen(name) + 1)
2038 {
2039 /* If the quarantine information shows up as an EA, we skip over it */
2040 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
2041 continue;
2042
2043 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, 0)) < 0)
2044 {
2045 ret = -1;
2046 continue;
2047 }
2048
2049 if (xa_size > bufsize)
2050 {
2051 void *tdptr = xa_dataptr;
2052 bufsize = xa_size;
2053 if ((xa_dataptr =
2054 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
2055 {
2056 free(tdptr);
2057 ret = -1;
2058 continue;
2059 }
2060 }
2061
2062 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, 0)) < 0)
2063 {
2064 ret = -1;
2065 continue;
2066 }
2067
2068 if (xa_size != asize)
2069 xa_size = asize;
2070
2071 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, 0) < 0)
2072 {
2073 ret = -1;
2074 continue;
2075 }
2076 }
2077 if (namebuf)
2078 free(namebuf);
2079 free((void *) xa_dataptr);
2080 return ret;
2081 }
2082
2083 /*
2084 * API interface into getting data from the opaque data type.
2085 */
2086 int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
2087 {
2088 if (ret == NULL)
2089 {
2090 errno = EFAULT;
2091 return -1;
2092 }
2093
2094 switch(flag)
2095 {
2096 case COPYFILE_STATE_SRC_FD:
2097 *(int*)ret = s->src_fd;
2098 break;
2099 case COPYFILE_STATE_DST_FD:
2100 *(int*)ret = s->dst_fd;
2101 break;
2102 case COPYFILE_STATE_SRC_FILENAME:
2103 *(char**)ret = s->src;
2104 break;
2105 case COPYFILE_STATE_DST_FILENAME:
2106 *(char**)ret = s->dst;
2107 break;
2108 case COPYFILE_STATE_QUARANTINE:
2109 *(qtn_file_t*)ret = s->qinfo;
2110 break;
2111 #if 0
2112 case COPYFILE_STATE_STATS:
2113 ret = s->stats.global;
2114 break;
2115 case COPYFILE_STATE_PROGRESS_CB:
2116 ret = s->callbacks.progress;
2117 break;
2118 #endif
2119 #ifdef COPYFILE_STATE_STATUS_CB
2120 case COPYFILE_STATE_STATUS_CB:
2121 *(copyfile_callback_t*)ret = s->statuscb;
2122 break;
2123 case COPYFILE_STATE_STATUS_CTX:
2124 *(void**)ret = s->ctx;
2125 break;
2126 case COPYFILE_STATE_COPIED:
2127 *(off_t*)ret = s->totalCopied;
2128 break;
2129 #endif
2130 default:
2131 errno = EINVAL;
2132 ret = NULL;
2133 return -1;
2134 }
2135 return 0;
2136 }
2137
2138 /*
2139 * Public API for setting state data (remember that the state is
2140 * an opaque data type).
2141 */
2142 int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
2143 {
2144 #define copyfile_set_string(DST, SRC) \
2145 do { \
2146 if (SRC != NULL) { \
2147 DST = strdup((char *)SRC); \
2148 } else { \
2149 if (DST != NULL) { \
2150 free(DST); \
2151 } \
2152 DST = NULL; \
2153 } \
2154 } while (0)
2155
2156 if (thing == NULL)
2157 {
2158 errno = EFAULT;
2159 return -1;
2160 }
2161
2162 switch(flag)
2163 {
2164 case COPYFILE_STATE_SRC_FD:
2165 s->src_fd = *(int*)thing;
2166 break;
2167 case COPYFILE_STATE_DST_FD:
2168 s->dst_fd = *(int*)thing;
2169 break;
2170 case COPYFILE_STATE_SRC_FILENAME:
2171 copyfile_set_string(s->src, thing);
2172 break;
2173 case COPYFILE_STATE_DST_FILENAME:
2174 copyfile_set_string(s->dst, thing);
2175 break;
2176 case COPYFILE_STATE_QUARANTINE:
2177 if (s->qinfo)
2178 {
2179 qtn_file_free(s->qinfo);
2180 s->qinfo = NULL;
2181 }
2182 if (*(qtn_file_t*)thing)
2183 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
2184 break;
2185 #if 0
2186 case COPYFILE_STATE_STATS:
2187 s->stats.global = thing;
2188 break;
2189 case COPYFILE_STATE_PROGRESS_CB:
2190 s->callbacks.progress = thing;
2191 break;
2192 #endif
2193 #ifdef COPYFILE_STATE_STATUS_CB
2194 case COPYFILE_STATE_STATUS_CB:
2195 s->statuscb = (copyfile_callback_t)thing;
2196 break;
2197 case COPYFILE_STATE_STATUS_CTX:
2198 s->ctx = (void*)thing;
2199 break;
2200 #endif
2201 default:
2202 errno = EINVAL;
2203 return -1;
2204 }
2205 return 0;
2206 #undef copyfile_set_string
2207 }
2208
2209
2210 /*
2211 * Make this a standalone program for testing purposes by
2212 * defining _COPYFILE_TEST.
2213 */
2214 #ifdef _COPYFILE_TEST
2215 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2216
2217 struct {char *s; int v;} opts[] = {
2218 COPYFILE_OPTION(ACL)
2219 COPYFILE_OPTION(STAT)
2220 COPYFILE_OPTION(XATTR)
2221 COPYFILE_OPTION(DATA)
2222 COPYFILE_OPTION(SECURITY)
2223 COPYFILE_OPTION(METADATA)
2224 COPYFILE_OPTION(ALL)
2225 COPYFILE_OPTION(NOFOLLOW_SRC)
2226 COPYFILE_OPTION(NOFOLLOW_DST)
2227 COPYFILE_OPTION(NOFOLLOW)
2228 COPYFILE_OPTION(EXCL)
2229 COPYFILE_OPTION(MOVE)
2230 COPYFILE_OPTION(UNLINK)
2231 COPYFILE_OPTION(PACK)
2232 COPYFILE_OPTION(UNPACK)
2233 COPYFILE_OPTION(CHECK)
2234 COPYFILE_OPTION(VERBOSE)
2235 COPYFILE_OPTION(DEBUG)
2236 {NULL, 0}
2237 };
2238
2239 int main(int c, char *v[])
2240 {
2241 int i;
2242 int flags = 0;
2243
2244 if (c < 3)
2245 errx(1, "insufficient arguments");
2246
2247 while(c-- > 3)
2248 {
2249 for (i = 0; opts[i].s != NULL; ++i)
2250 {
2251 if (strcasecmp(opts[i].s, v[c]) == 0)
2252 {
2253 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
2254 flags |= opts[i].v;
2255 break;
2256 }
2257 }
2258 }
2259
2260 return copyfile(v[1], v[2], NULL, flags);
2261 }
2262 #endif
2263 /*
2264 * Apple Double Create
2265 *
2266 * Create an Apple Double "._" file from a file's extented attributes
2267 *
2268 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2269 */
2270
2271
2272 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2273
2274 #define XATTR_MAXATTRLEN (4*1024)
2275
2276
2277 /*
2278 Typical "._" AppleDouble Header File layout:
2279 ------------------------------------------------------------
2280 MAGIC 0x00051607
2281 VERSION 0x00020000
2282 FILLER 0
2283 COUNT 2
2284 .-- AD ENTRY[0] Finder Info Entry (must be first)
2285 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2286 | '-> FINDER INFO
2287 | ///////////// Fixed Size Data (32 bytes)
2288 | EXT ATTR HDR
2289 | /////////////
2290 | ATTR ENTRY[0] --.
2291 | ATTR ENTRY[1] --+--.
2292 | ATTR ENTRY[2] --+--+--.
2293 | ... | | |
2294 | ATTR ENTRY[N] --+--+--+--.
2295 | ATTR DATA 0 <-' | | |
2296 | //////////// | | |
2297 | ATTR DATA 1 <----' | |
2298 | ///////////// | |
2299 | ATTR DATA 2 <-------' |
2300 | ///////////// |
2301 | ... |
2302 | ATTR DATA N <----------'
2303 | /////////////
2304 | Attribute Free Space
2305 |
2306 '----> RESOURCE FORK
2307 ///////////// Variable Sized Data
2308 /////////////
2309 /////////////
2310 /////////////
2311 /////////////
2312 /////////////
2313 ...
2314 /////////////
2315
2316 ------------------------------------------------------------
2317
2318 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2319 stored as part of the Finder Info. The length in the Finder
2320 Info AppleDouble entry includes the length of the extended
2321 attribute header, attribute entries, and attribute data.
2322 */
2323
2324
2325 /*
2326 * On Disk Data Structures
2327 *
2328 * Note: Motorola 68K alignment and big-endian.
2329 *
2330 * See RFC 1740 for additional information about the AppleDouble file format.
2331 *
2332 */
2333
2334 #define ADH_MAGIC 0x00051607
2335 #define ADH_VERSION 0x00020000
2336 #define ADH_MACOSX "Mac OS X "
2337
2338 /*
2339 * AppleDouble Entry ID's
2340 */
2341 #define AD_DATA 1 /* Data fork */
2342 #define AD_RESOURCE 2 /* Resource fork */
2343 #define AD_REALNAME 3 /* File's name on home file system */
2344 #define AD_COMMENT 4 /* Standard Mac comment */
2345 #define AD_ICONBW 5 /* Mac black & white icon */
2346 #define AD_ICONCOLOR 6 /* Mac color icon */
2347 #define AD_UNUSED 7 /* Not used */
2348 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2349 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2350 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2351 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2352 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2353 #define AD_AFPNAME 13 /* Short name on AFP server */
2354 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2355 #define AD_AFPDIRID 15 /* AFP directory ID */
2356 #define AD_ATTRIBUTES AD_FINDERINFO
2357
2358
2359 #define ATTR_FILE_PREFIX "._"
2360 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2361
2362 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2363
2364 /* Implementation Limits */
2365 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2366 #define ATTR_MAX_NAME_LEN 128
2367 #define ATTR_MAX_HDR_SIZE (65536+18)
2368
2369 /*
2370 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2371 * size supported (including the attribute entries). All of
2372 * the attribute entries must reside within this limit.
2373 */
2374
2375
2376 #define FINDERINFOSIZE 32
2377
2378 typedef struct apple_double_entry
2379 {
2380 u_int32_t type; /* entry type: see list, 0 invalid */
2381 u_int32_t offset; /* entry data offset from the beginning of the file. */
2382 u_int32_t length; /* entry data length in bytes. */
2383 } __attribute__((aligned(2), packed)) apple_double_entry_t;
2384
2385
2386 typedef struct apple_double_header
2387 {
2388 u_int32_t magic; /* == ADH_MAGIC */
2389 u_int32_t version; /* format version: 2 = 0x00020000 */
2390 u_int32_t filler[4];
2391 u_int16_t numEntries; /* number of entries which follow */
2392 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
2393 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
2394 u_int8_t pad[2]; /* get better alignment inside attr_header */
2395 } __attribute__((aligned(2), packed)) apple_double_header_t;
2396
2397
2398 /* Entries are aligned on 4 byte boundaries */
2399 typedef struct attr_entry
2400 {
2401 u_int32_t offset; /* file offset to data */
2402 u_int32_t length; /* size of attribute data */
2403 u_int16_t flags;
2404 u_int8_t namelen; /* length of name including NULL termination char */
2405 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2406 } __attribute__((aligned(2), packed)) attr_entry_t;
2407
2408
2409
2410 /* Header + entries must fit into 64K */
2411 typedef struct attr_header
2412 {
2413 apple_double_header_t appledouble;
2414 u_int32_t magic; /* == ATTR_HDR_MAGIC */
2415 u_int32_t debug_tag; /* for debugging == file id of owning file */
2416 u_int32_t total_size; /* total size of attribute header + entries + data */
2417 u_int32_t data_start; /* file offset to attribute data area */
2418 u_int32_t data_length; /* length of attribute data area */
2419 u_int32_t reserved[3];
2420 u_int16_t flags;
2421 u_int16_t num_attrs;
2422 } __attribute__((aligned(2), packed)) attr_header_t;
2423
2424 /* Empty Resource Fork Header */
2425 /* This comes by way of xnu's vfs_xattr.c */
2426 typedef struct rsrcfork_header {
2427 u_int32_t fh_DataOffset;
2428 u_int32_t fh_MapOffset;
2429 u_int32_t fh_DataLength;
2430 u_int32_t fh_MapLength;
2431 u_int8_t systemData[112];
2432 u_int8_t appData[128];
2433 u_int32_t mh_DataOffset;
2434 u_int32_t mh_MapOffset;
2435 u_int32_t mh_DataLength;
2436 u_int32_t mh_MapLength;
2437 u_int32_t mh_Next;
2438 u_int16_t mh_RefNum;
2439 u_int8_t mh_Attr;
2440 u_int8_t mh_InMemoryAttr;
2441 u_int16_t mh_Types;
2442 u_int16_t mh_Names;
2443 u_int16_t typeCount;
2444 } __attribute__((aligned(2), packed)) rsrcfork_header_t;
2445 #define RF_FIRST_RESOURCE 256
2446 #define RF_NULL_MAP_LENGTH 30
2447 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2448
2449 static const rsrcfork_header_t empty_rsrcfork_header = {
2450 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset
2451 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset
2452 0, // fh_DataLength
2453 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength
2454 { RF_EMPTY_TAG, }, // systemData
2455 { 0 }, // appData
2456 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset
2457 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset
2458 0, // mh_DataLength
2459 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength
2460 0, // mh_Next
2461 0, // mh_RefNum
2462 0, // mh_Attr
2463 0, // mh_InMemoryAttr
2464 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types
2465 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names
2466 OSSwapHostToBigInt16(-1), // typeCount
2467 };
2468
2469 #define SWAP16(x) OSSwapBigToHostInt16(x)
2470 #define SWAP32(x) OSSwapBigToHostInt32(x)
2471 #define SWAP64(x) OSSwapBigToHostInt64(x)
2472
2473 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2474
2475 #define ATTR_ENTRY_LENGTH(namelen) \
2476 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2477
2478 #define ATTR_NEXT(ae) \
2479 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2480
2481 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2482
2483 /*
2484 * Endian swap Apple Double header
2485 */
2486 static void
2487 swap_adhdr(apple_double_header_t *adh)
2488 {
2489 #if BYTE_ORDER == LITTLE_ENDIAN
2490 int count;
2491 int i;
2492
2493 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
2494
2495 adh->magic = SWAP32 (adh->magic);
2496 adh->version = SWAP32 (adh->version);
2497 adh->numEntries = SWAP16 (adh->numEntries);
2498
2499 for (i = 0; i < count; i++)
2500 {
2501 adh->entries[i].type = SWAP32 (adh->entries[i].type);
2502 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
2503 adh->entries[i].length = SWAP32 (adh->entries[i].length);
2504 }
2505 #else
2506 (void)adh;
2507 #endif
2508 }
2509
2510 /*
2511 * Endian swap extended attributes header
2512 */
2513 static void
2514 swap_attrhdr(attr_header_t *ah)
2515 {
2516 #if BYTE_ORDER == LITTLE_ENDIAN
2517 attr_entry_t *ae;
2518 int count;
2519 int i;
2520
2521 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
2522
2523 ah->magic = SWAP32 (ah->magic);
2524 ah->debug_tag = SWAP32 (ah->debug_tag);
2525 ah->total_size = SWAP32 (ah->total_size);
2526 ah->data_start = SWAP32 (ah->data_start);
2527 ah->data_length = SWAP32 (ah->data_length);
2528 ah->flags = SWAP16 (ah->flags);
2529 ah->num_attrs = SWAP16 (ah->num_attrs);
2530
2531 ae = (attr_entry_t *)(&ah[1]);
2532 for (i = 0; i < count; i++)
2533 {
2534 attr_entry_t *next = ATTR_NEXT(ae);
2535 ae->offset = SWAP32 (ae->offset);
2536 ae->length = SWAP32 (ae->length);
2537 ae->flags = SWAP16 (ae->flags);
2538 ae = next;
2539 }
2540 #else
2541 (void)ah;
2542 #endif
2543 }
2544
2545 static const u_int32_t emptyfinfo[8] = {0};
2546
2547 /*
2548 * Given an Apple Double file in src, turn it into a
2549 * normal file (possibly with multiple forks, EAs, and
2550 * ACLs) in dst.
2551 */
2552 static int copyfile_unpack(copyfile_state_t s)
2553 {
2554 ssize_t bytes;
2555 void * buffer, * endptr;
2556 apple_double_header_t *adhdr;
2557 ssize_t hdrsize;
2558 int error = 0;
2559
2560 if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
2561 hdrsize = (ssize_t)s->sb.st_size;
2562 else
2563 hdrsize = ATTR_MAX_HDR_SIZE;
2564
2565 buffer = calloc(1, hdrsize);
2566 if (buffer == NULL) {
2567 copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL", hdrsize);
2568 error = -1;
2569 goto exit;
2570 } else
2571 endptr = (char*)buffer + hdrsize;
2572
2573 bytes = pread(s->src_fd, buffer, hdrsize, 0);
2574
2575 if (bytes < 0)
2576 {
2577 copyfile_debug(1, "pread returned: %d", bytes);
2578 error = -1;
2579 goto exit;
2580 }
2581 if (bytes < hdrsize)
2582 {
2583 copyfile_debug(1,
2584 "pread couldn't read entire header: %d of %d",
2585 (int)bytes, (int)s->sb.st_size);
2586 error = -1;
2587 goto exit;
2588 }
2589 adhdr = (apple_double_header_t *)buffer;
2590
2591 /*
2592 * Check for Apple Double file.
2593 */
2594 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
2595 SWAP32(adhdr->magic) != ADH_MAGIC ||
2596 SWAP32(adhdr->version) != ADH_VERSION ||
2597 SWAP16(adhdr->numEntries) != 2 ||
2598 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
2599 {
2600 if (COPYFILE_VERBOSE & s->flags)
2601 copyfile_warn("Not a valid Apple Double header");
2602 error = -1;
2603 goto exit;
2604 }
2605 swap_adhdr(adhdr);
2606
2607 /*
2608 * Remove any extended attributes on the target.
2609 */
2610
2611 if (COPYFILE_XATTR & s->flags)
2612 {
2613 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2614 {
2615 char *namebuf, *name;
2616
2617 if ((namebuf = (char*) malloc(bytes)) == NULL)
2618 {
2619 s->err = ENOMEM;
2620 goto exit;
2621 }
2622 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
2623
2624 if (bytes > 0)
2625 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
2626 (void)fremovexattr(s->dst_fd, name, 0);
2627
2628 free(namebuf);
2629 }
2630 else if (bytes < 0)
2631 {
2632 if (errno != ENOTSUP && errno != EPERM)
2633 goto exit;
2634 }
2635 }
2636
2637 /*
2638 * Extract the extended attributes.
2639 *
2640 * >>> WARNING <<<
2641 * This assumes that the data is already in memory (not
2642 * the case when there are lots of attributes or one of
2643 * the attributes is very large.
2644 */
2645 if (adhdr->entries[0].length > FINDERINFOSIZE)
2646 {
2647 attr_header_t *attrhdr;
2648 attr_entry_t *entry;
2649 int count;
2650 int i;
2651
2652 if ((size_t)hdrsize < sizeof(attr_header_t)) {
2653 copyfile_warn("bad attribute header: %u < %u", hdrsize, sizeof(attr_header_t));
2654 error = -1;
2655 goto exit;
2656 }
2657
2658 attrhdr = (attr_header_t *)buffer;
2659 swap_attrhdr(attrhdr);
2660 if (attrhdr->magic != ATTR_HDR_MAGIC)
2661 {
2662 if (COPYFILE_VERBOSE & s->flags)
2663 copyfile_warn("bad attribute header");
2664 error = -1;
2665 goto exit;
2666 }
2667 count = attrhdr->num_attrs;
2668 entry = (attr_entry_t *)&attrhdr[1];
2669
2670 for (i = 0; i < count; i++)
2671 {
2672 void * dataptr;
2673
2674 /*
2675 * First we do some simple sanity checking.
2676 * +) See if entry is within the buffer's range;
2677 *
2678 * +) Check the attribute name length; if it's longer than the
2679 * maximum, we truncate it down. (We could error out as well;
2680 * I'm not sure which is the better way to go here.)
2681 *
2682 * +) If, given the name length, it goes beyond the end of
2683 * the buffer, error out.
2684 *
2685 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2686 * truncated the name length above, we truncate the name here.)
2687 *
2688 * +) If entry->offset is so large that it causes dataptr to
2689 * go beyond the end of the buffer -- or, worse, so large that
2690 * it wraps around! -- we error out.
2691 *
2692 * +) If entry->length would cause the entry to go beyond the
2693 * end of the buffer (or, worse, wrap around to before it),
2694 * *or* if the length is larger than the hdrsize, we error out.
2695 * (An explanation of that: what we're checking for there is
2696 * the small range of values such that offset+length would cause
2697 * it to go beyond endptr, and then wrap around past buffer. We
2698 * care about this because we are passing entry->length down to
2699 * fgetxattr() below, and an erroneously large value could cause
2700 * problems there. By making sure that it's less than hdrsize,
2701 * which has already been sanity-checked above, we're safe.
2702 * That may mean that the check against < buffer is unnecessary.)
2703 */
2704 if ((void*)entry >= endptr || (void*)entry < buffer) {
2705 if (COPYFILE_VERBOSE & s->flags)
2706 copyfile_warn("Incomplete or corrupt attribute entry");
2707 error = -1;
2708 s->err = EINVAL;
2709 goto exit;
2710 }
2711
2712 if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
2713 if (COPYFILE_VERBOSE & s->flags)
2714 copyfile_warn("Incomplete or corrupt attribute entry");
2715 error = -1;
2716 s->err = EINVAL;
2717 goto exit;
2718 }
2719
2720 if (entry->namelen < 2) {
2721 if (COPYFILE_VERBOSE & s->flags)
2722 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
2723 error = -1;
2724 s->err = EINVAL;
2725 goto exit;
2726 }
2727
2728 if (entry->namelen > XATTR_MAXNAMELEN + 1) {
2729 if (COPYFILE_VERBOSE & s->flags)
2730 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
2731 error = -1;
2732 s->err = EINVAL;
2733 goto exit;
2734 }
2735
2736 if ((void*)(entry->name + entry->namelen) > endptr) {
2737 if (COPYFILE_VERBOSE & s->flags)
2738 copyfile_warn("Incomplete or corrupt attribute entry");
2739 error = -1;
2740 s->err = EINVAL;
2741 goto exit;
2742 }
2743
2744 /* Because namelen includes the NUL, we check one byte back */
2745 if (entry->name[entry->namelen-1] != 0) {
2746 if (COPYFILE_VERBOSE & s->flags)
2747 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
2748 error = -1;
2749 s->err = EINVAL;
2750 goto exit;
2751 }
2752
2753 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
2754 entry->name, entry->length, entry->offset);
2755
2756 dataptr = (char *)attrhdr + entry->offset;
2757
2758 if (dataptr > endptr || dataptr < buffer) {
2759 copyfile_debug(1, "Entry %d overflows: offset = %u", entry->offset);
2760 error = -1;
2761 s->err = EINVAL; /* Invalid buffer */
2762 goto exit;
2763 }
2764 if (((char*)dataptr + entry->length) > (char*)endptr ||
2765 (((char*)dataptr + entry->length) < (char*)buffer) ||
2766 (entry->length > (size_t)hdrsize)) {
2767 if (COPYFILE_VERBOSE & s->flags)
2768 copyfile_warn("Incomplete or corrupt attribute entry");
2769 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
2770 entry->offset, entry->length);
2771 error = -1;
2772 s->err = EINVAL; /* Invalid buffer */
2773 goto exit;
2774 }
2775
2776 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
2777 {
2778 qtn_file_t tqinfo = NULL;
2779
2780 if (s->qinfo == NULL)
2781 {
2782 tqinfo = qtn_file_alloc();
2783 if (tqinfo)
2784 {
2785 int x;
2786 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
2787 {
2788 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
2789 qtn_file_free(tqinfo);
2790 tqinfo = NULL;
2791 }
2792 }
2793 }
2794 else
2795 {
2796 tqinfo = s->qinfo;
2797 }
2798 if (tqinfo)
2799 {
2800 int x;
2801 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
2802 if (x != 0)
2803 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
2804 }
2805 if (tqinfo && !s->qinfo)
2806 {
2807 qtn_file_free(tqinfo);
2808 }
2809 }
2810 /* Look for ACL data */
2811 else if (COPYFILE_ACL & s->flags && strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
2812 {
2813 acl_t acl;
2814 struct stat sb;
2815 int retry = 1;
2816 char *tcp = dataptr;
2817
2818 /*
2819 * acl_from_text() requires a NUL-terminated string. The ACL EA,
2820 * however, may not be NUL-terminated. So in that case, we need to
2821 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
2822 */
2823 if (tcp[entry->length - 1] != 0) {
2824 char *tmpstr = malloc(entry->length + 1);
2825 if (tmpstr == NULL) {
2826 error = -1;
2827 goto exit;
2828 }
2829 strlcpy(tmpstr, tcp, entry->length + 1);
2830 acl = acl_from_text(tmpstr);
2831 free(tmpstr);
2832 } else {
2833 acl = acl_from_text(tcp);
2834 }
2835
2836 if (acl != NULL)
2837 {
2838 filesec_t fsec_tmp;
2839
2840 if ((fsec_tmp = filesec_init()) == NULL)
2841 error = -1;
2842 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
2843 error = -1;
2844 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
2845 error = -1;
2846 else {
2847 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
2848 {
2849 if (errno == ENOTSUP)
2850 {
2851 if (retry && !copyfile_unset_acl(s))
2852 {
2853 retry = 0;
2854 continue;
2855 }
2856 }
2857 copyfile_warn("setting security information");
2858 error = -1;
2859 break;
2860 }
2861 }
2862 acl_free(acl);
2863 filesec_free(fsec_tmp);
2864
2865 if (error == -1)
2866 goto exit;
2867 }
2868 }
2869 /* And, finally, everything else */
2870 else if (COPYFILE_XATTR & s->flags) {
2871 if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
2872 if (COPYFILE_VERBOSE & s->flags)
2873 copyfile_warn("error %d setting attribute %s", error, entry->name);
2874 error = -1;
2875 goto exit;
2876 }
2877 }
2878 entry = ATTR_NEXT(entry);
2879 }
2880 }
2881
2882 /*
2883 * Extract the Finder Info.
2884 */
2885 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
2886 error = -1;
2887 goto exit;
2888 }
2889
2890 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
2891 {
2892 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
2893 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
2894 if (error)
2895 goto exit;
2896 }
2897
2898 /*
2899 * Extract the Resource Fork.
2900 */
2901 if (adhdr->entries[1].type == AD_RESOURCE &&
2902 adhdr->entries[1].length > 0)
2903 {
2904 void * rsrcforkdata = NULL;
2905 size_t length;
2906 off_t offset;
2907 struct stat sb;
2908 struct timeval tval[2];
2909
2910 length = adhdr->entries[1].length;
2911 offset = adhdr->entries[1].offset;
2912 rsrcforkdata = malloc(length);
2913
2914 if (rsrcforkdata == NULL) {
2915 copyfile_debug(1, "could not allocate %u bytes for rsrcforkdata",
2916 length);
2917 error = -1;
2918 goto bad;
2919 }
2920
2921 if (fstat(s->dst_fd, &sb) < 0)
2922 {
2923 copyfile_debug(1, "couldn't stat destination file");
2924 error = -1;
2925 goto bad;
2926 }
2927
2928 bytes = pread(s->src_fd, rsrcforkdata, length, offset);
2929 if (bytes < (ssize_t)length)
2930 {
2931 if (bytes == -1)
2932 {
2933 copyfile_debug(1, "couldn't read resource fork");
2934 }
2935 else
2936 {
2937 copyfile_debug(1,
2938 "couldn't read resource fork (only read %d bytes of %d)",
2939 (int)bytes, (int)length);
2940 }
2941 error = -1;
2942 goto bad;
2943 }
2944 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
2945 if (error)
2946 {
2947 /*
2948 * For filesystems that do not natively support named attributes,
2949 * the kernel creates an AppleDouble file that -- for compatabilty
2950 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
2951 * structure that says there are no resources. So, if fsetxattr has
2952 * failed, and the resource fork is that empty structure, *and* the
2953 * target file is a directory, then we do nothing with it.
2954 */
2955 if ((bytes == sizeof(rsrcfork_header_t)) &&
2956 ((sb.st_mode & S_IFMT) == S_IFDIR) &&
2957 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
2958 copyfile_debug(2, "not setting empty resource fork on directory");
2959 error = errno = 0;
2960 goto bad;
2961 }
2962 copyfile_debug(1, "error %d setting resource fork attribute", error);
2963 error = -1;
2964 goto bad;
2965 }
2966 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
2967 XATTR_RESOURCEFORK_NAME, (int)length);
2968
2969 if (!(s->flags & COPYFILE_STAT))
2970 {
2971 tval[0].tv_sec = sb.st_atime;
2972 tval[1].tv_sec = sb.st_mtime;
2973 tval[0].tv_usec = tval[1].tv_usec = 0;
2974
2975 if (futimes(s->dst_fd, tval))
2976 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
2977 }
2978 bad:
2979 if (rsrcforkdata)
2980 free(rsrcforkdata);
2981 }
2982
2983 if (COPYFILE_STAT & s->flags)
2984 {
2985 error = copyfile_stat(s);
2986 }
2987 exit:
2988 if (buffer) free(buffer);
2989 return error;
2990 }
2991
2992 static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
2993 {
2994 int ret = 0;
2995 char qbuf[QTN_SERIALIZED_DATA_MAX];
2996 size_t qlen = sizeof(qbuf);
2997
2998 if (s->qinfo == NULL)
2999 {
3000 ret = -1;
3001 goto done;
3002 }
3003
3004 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
3005 {
3006 ret = -1;
3007 goto done;
3008 }
3009
3010 *buf = malloc(qlen);
3011 if (*buf)
3012 {
3013 memcpy(*buf, qbuf, qlen);
3014 *len = qlen;
3015 }
3016 done:
3017 return ret;
3018 }
3019
3020 static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
3021 {
3022 int ret = 0;
3023 acl_t acl = NULL;
3024 char *acl_text;
3025
3026 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
3027 {
3028 if (errno != ENOENT)
3029 {
3030 ret = -1;
3031 if (COPYFILE_VERBOSE & s->flags)
3032 copyfile_warn("getting acl");
3033 }
3034 *len = 0;
3035 goto exit;
3036 }
3037
3038 if ((acl_text = acl_to_text(acl, len)) != NULL)
3039 {
3040 /*
3041 * acl_to_text() doesn't include the NUL at the endo
3042 * in it's count (*len). It does, however, promise to
3043 * return a valid C string, so we need to up the count
3044 * by 1.
3045 */
3046 *len = *len + 1;
3047 *buf = malloc(*len);
3048 if (*buf)
3049 memcpy(*buf, acl_text, *len);
3050 else
3051 *len = 0;
3052 acl_free(acl_text);
3053 }
3054 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
3055 exit:
3056 if (acl)
3057 acl_free(acl);
3058 return ret;
3059 }
3060
3061 static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
3062 {
3063 ssize_t datasize;
3064 char *databuf = NULL;
3065 int ret = 0;
3066
3067 /* Get the resource fork size */
3068 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
3069 {
3070 if (COPYFILE_VERBOSE & s->flags)
3071 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
3072 return -1;
3073 }
3074
3075 if (datasize > INT_MAX) {
3076 s->err = EINVAL;
3077 ret = -1;
3078 goto done;
3079 }
3080
3081 if ((databuf = malloc(datasize)) == NULL)
3082 {
3083 copyfile_warn("malloc");
3084 ret = -1;
3085 goto done;
3086 }
3087
3088 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
3089 {
3090 if (COPYFILE_VERBOSE & s->flags)
3091 copyfile_warn("couldn't read entire resource fork");
3092 ret = -1;
3093 goto done;
3094 }
3095
3096 /* Write the resource fork to disk. */
3097 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
3098 {
3099 if (COPYFILE_VERBOSE & s->flags)
3100 copyfile_warn("couldn't write resource fork");
3101 }
3102 copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
3103 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
3104 filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
3105
3106 done:
3107 if (databuf)
3108 free(databuf);
3109
3110 return ret;
3111 }
3112
3113 /*
3114 * The opposite of copyfile_unpack(), obviously.
3115 */
3116 static int copyfile_pack(copyfile_state_t s)
3117 {
3118 char *attrnamebuf = NULL, *endnamebuf;
3119 void *databuf = NULL;
3120 attr_header_t *filehdr, *endfilehdr;
3121 attr_entry_t *entry;
3122 ssize_t listsize = 0;
3123 char *nameptr;
3124 size_t namelen;
3125 size_t entrylen;
3126 ssize_t datasize;
3127 size_t offset = 0;
3128 int hasrsrcfork = 0;
3129 int error = 0;
3130 int seenq = 0; // Have we seen any quarantine info already?
3131
3132 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
3133 if (filehdr == NULL) {
3134 error = -1;
3135 goto exit;
3136 } else {
3137 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
3138 }
3139
3140 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
3141 if (attrnamebuf == NULL) {
3142 error = -1;
3143 goto exit;
3144 } else {
3145 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
3146 }
3147
3148 /*
3149 * Fill in the Apple Double Header defaults.
3150 */
3151 filehdr->appledouble.magic = ADH_MAGIC;
3152 filehdr->appledouble.version = ADH_VERSION;
3153 filehdr->appledouble.numEntries = 2;
3154 filehdr->appledouble.entries[0].type = AD_FINDERINFO;
3155 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo);
3156 filehdr->appledouble.entries[0].length = FINDERINFOSIZE;
3157 filehdr->appledouble.entries[1].type = AD_RESOURCE;
3158 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad);
3159 filehdr->appledouble.entries[1].length = 0;
3160 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
3161
3162 /*
3163 * Fill in the initial Attribute Header.
3164 */
3165 filehdr->magic = ATTR_HDR_MAGIC;
3166 filehdr->debug_tag = (u_int32_t)s->sb.st_ino;
3167 filehdr->data_start = (u_int32_t)sizeof(attr_header_t);
3168
3169 /*
3170 * Collect the attribute names.
3171 */
3172 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3173
3174 /*
3175 * Test if there are acls to copy
3176 */
3177 if (COPYFILE_ACL & s->flags)
3178 {
3179 acl_t temp_acl = NULL;
3180 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
3181 {
3182 copyfile_debug(2, "no acl entries found (errno = %d)", errno);
3183 } else
3184 {
3185 offset = strlen(XATTR_SECURITY_NAME) + 1;
3186 strcpy(attrnamebuf, XATTR_SECURITY_NAME);
3187 }
3188 if (temp_acl)
3189 acl_free(temp_acl);
3190 }
3191
3192 if (COPYFILE_XATTR & s->flags)
3193 {
3194 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3195 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
3196 {
3197 copyfile_debug(2, "no extended attributes found (%d)", errno);
3198 }
3199 if (listsize > left)
3200 {
3201 copyfile_debug(1, "extended attribute list too long");
3202 listsize = left;
3203 }
3204
3205 listsize += offset;
3206 endnamebuf = attrnamebuf + listsize;
3207 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
3208 error = -1;
3209 goto exit;
3210 }
3211
3212 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
3213 {
3214 namelen = strlen(nameptr) + 1;
3215 /* Skip over FinderInfo or Resource Fork names */
3216 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
3217 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
3218 continue;
3219 }
3220 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
3221 seenq = 1;
3222 }
3223
3224 /* The system should prevent this from happening, but... */
3225 if (namelen > XATTR_MAXNAMELEN + 1) {
3226 namelen = XATTR_MAXNAMELEN + 1;
3227 }
3228 entry->namelen = namelen;
3229 entry->flags = 0;
3230 if (nameptr + namelen > endnamebuf) {
3231 error = -1;
3232 goto exit;
3233 }
3234 bcopy(nameptr, &entry->name[0], namelen);
3235 copyfile_debug(2, "copied name [%s]", entry->name);
3236
3237 entrylen = ATTR_ENTRY_LENGTH(namelen);
3238 entry = (attr_entry_t *)(((char *)entry) + entrylen);
3239
3240 if ((void*)entry >= (void*)endfilehdr) {
3241 error = -1;
3242 goto exit;
3243 }
3244
3245 /* Update the attributes header. */
3246 filehdr->num_attrs++;
3247 filehdr->data_start += (u_int32_t)entrylen;
3248 }
3249 }
3250
3251 /*
3252 * If we have any quarantine data, we always pack it.
3253 * But if we've already got it in the EA list, don't put it in again.
3254 */
3255 if (s->qinfo && !seenq)
3256 {
3257 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3258 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3259 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
3260 }
3261
3262 seenq = 0;
3263 /*
3264 * Collect the attribute data.
3265 */
3266 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3267
3268 for (nameptr = attrnamebuf; nameptr < attrnamebuf + listsize; nameptr += namelen + 1)
3269 {
3270 namelen = strlen(nameptr);
3271
3272 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
3273 copyfile_pack_acl(s, &databuf, &datasize);
3274 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
3275 {
3276 copyfile_pack_quarantine(s, &databuf, &datasize);
3277 }
3278 /* Check for Finder Info. */
3279 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
3280 {
3281 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
3282 if (datasize < 0)
3283 {
3284 if (COPYFILE_VERBOSE & s->flags)
3285 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3286 } else if (datasize != 32)
3287 {
3288 if (COPYFILE_VERBOSE & s->flags)
3289 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
3290 } else
3291 {
3292 if (COPYFILE_VERBOSE & s->flags)
3293 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3294 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
3295 }
3296 continue; /* finder info doesn't have an attribute entry */
3297 }
3298 /* Check for Resource Fork. */
3299 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
3300 {
3301 hasrsrcfork = 1;
3302 continue;
3303 } else
3304 {
3305 /* Just a normal attribute. */
3306 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
3307 if (datasize == 0)
3308 goto next;
3309 if (datasize < 0)
3310 {
3311 if (COPYFILE_VERBOSE & s->flags)
3312 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3313 goto next;
3314 }
3315 if (datasize > XATTR_MAXATTRLEN)
3316 {
3317 if (COPYFILE_VERBOSE & s->flags)
3318 copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
3319 goto next;
3320 }
3321 databuf = malloc(datasize);
3322 if (databuf == NULL) {
3323 error = -1;
3324 continue;
3325 }
3326 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
3327 }
3328
3329 entry->length = (u_int32_t)datasize;
3330 entry->offset = filehdr->data_start + filehdr->data_length;
3331
3332 filehdr->data_length += (u_int32_t)datasize;
3333 /*
3334 * >>> WARNING <<<
3335 * This assumes that the data is fits in memory (not
3336 * the case when there are lots of attributes or one of
3337 * the attributes is very large.
3338 */
3339 if (entry->offset > ATTR_MAX_SIZE ||
3340 (entry->offset + datasize > ATTR_MAX_SIZE)) {
3341 error = 1;
3342 } else {
3343 bcopy(databuf, (char*)filehdr + entry->offset, datasize);
3344 }
3345 free(databuf);
3346
3347 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
3348 next:
3349 /* bump to next entry */
3350 entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
3351 entry = (attr_entry_t *)((char *)entry + entrylen);
3352 }
3353
3354 if (filehdr->data_length > 0)
3355 {
3356 /* Now we know where the resource fork data starts. */
3357 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
3358
3359 /* We also know the size of the "Finder Info entry. */
3360 filehdr->appledouble.entries[0].length =
3361 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
3362
3363 filehdr->total_size = filehdr->appledouble.entries[1].offset;
3364 }
3365
3366 /* Copy Resource Fork. */
3367 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
3368 goto exit;
3369
3370 /* Write the header to disk. */
3371 datasize = filehdr->appledouble.entries[1].offset;
3372
3373 swap_adhdr(&filehdr->appledouble);
3374 swap_attrhdr(filehdr);
3375
3376 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
3377 {
3378 if (COPYFILE_VERBOSE & s->flags)
3379 copyfile_warn("couldn't write file header");
3380 error = -1;
3381 goto exit;
3382 }
3383 exit:
3384 if (filehdr) free(filehdr);
3385 if (attrnamebuf) free(attrnamebuf);
3386
3387 if (error)
3388 return error;
3389 else
3390 return copyfile_stat(s);
3391 }