]> granicus.if.org Git - shadow/blob - libmisc/copydir.c
93f2b4f20102b6dc7ece9883facaf60e9a055cc3
[shadow] / libmisc / copydir.c
1 /*
2  * Copyright (c) 1991 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2001, Marek Michałkiewicz
4  * Copyright (c) 2003 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2010, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #ident "$Id$"
36
37 #include <assert.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include "prototypes.h"
44 #include "defines.h"
45 #ifdef WITH_SELINUX
46 #include <selinux/selinux.h>
47 #endif                          /* WITH_SELINUX */
48 #if defined(WITH_ACL) || defined(WITH_ATTR)
49 #include <attr/error_context.h>
50 #endif                          /* WITH_ACL || WITH_ATTR */
51 #ifdef WITH_ACL
52 #include <acl/libacl.h>
53 #endif                          /* WITH_ACL */
54 #ifdef WITH_ATTR
55 #include <attr/libattr.h>
56 #endif                          /* WITH_ATTR */
57
58 #ifdef WITH_SELINUX
59 static bool selinux_checked = false;
60 static bool selinux_enabled;
61 #endif                          /* WITH_SELINUX */
62
63 static /*@null@*/const char *src_orig;
64 static /*@null@*/const char *dst_orig;
65
66 struct link_name {
67         dev_t ln_dev;
68         ino_t ln_ino;
69         nlink_t ln_count;
70         char *ln_name;
71         /*@dependent@*/struct link_name *ln_next;
72 };
73 static /*@exposed@*/struct link_name *links;
74
75 static int copy_entry (const char *src, const char *dst,
76                        bool reset_selinux,
77                        uid_t old_uid, uid_t new_uid,
78                        gid_t old_gid, gid_t new_gid);
79 static int copy_dir (const char *src, const char *dst,
80                      bool reset_selinux,
81                      const struct stat *statp, const struct timeval mt[],
82                      uid_t old_uid, uid_t new_uid,
83                      gid_t old_gid, gid_t new_gid);
84 #ifdef  S_IFLNK
85 static /*@null@*/char *readlink_malloc (const char *filename);
86 static int copy_symlink (const char *src, const char *dst,
87                          unused bool reset_selinux,
88                          const struct stat *statp, const struct timeval mt[],
89                          uid_t old_uid, uid_t new_uid,
90                          gid_t old_gid, gid_t new_gid);
91 #endif                          /* S_IFLNK */
92 static int copy_hardlink (const char *dst,
93                           unused bool reset_selinux,
94                           struct link_name *lp);
95 static int copy_special (const char *src, const char *dst,
96                          bool reset_selinux,
97                          const struct stat *statp, const struct timeval mt[],
98                          uid_t old_uid, uid_t new_uid,
99                          gid_t old_gid, gid_t new_gid);
100 static int copy_file (const char *src, const char *dst,
101                       bool reset_selinux,
102                       const struct stat *statp, const struct timeval mt[],
103                       uid_t old_uid, uid_t new_uid,
104                       gid_t old_gid, gid_t new_gid);
105 static int chown_if_needed (const char *dst, const struct stat *statp,
106                             uid_t old_uid, uid_t new_uid,
107                             gid_t old_gid, gid_t new_gid);
108 static int lchown_if_needed (const char *dst, const struct stat *statp,
109                              uid_t old_uid, uid_t new_uid,
110                              gid_t old_gid, gid_t new_gid);
111 static int fchown_if_needed (int fdst, const struct stat *statp,
112                              uid_t old_uid, uid_t new_uid,
113                              gid_t old_gid, gid_t new_gid);
114
115 #ifdef WITH_SELINUX
116 /*
117  * set_selinux_file_context - Set the security context before any file or
118  *                            directory creation.
119  *
120  *      set_selinux_file_context () should be called before any creation
121  *      of file, symlink, directory, ...
122  *
123  *      Callers may have to Reset SELinux to create files with default
124  *      contexts with reset_selinux_file_context
125  */
126 int set_selinux_file_context (const char *dst_name)
127 {
128         /*@null@*/security_context_t scontext = NULL;
129
130         if (!selinux_checked) {
131                 selinux_enabled = is_selinux_enabled () > 0;
132                 selinux_checked = true;
133         }
134
135         if (selinux_enabled) {
136                 /* Get the default security context for this file */
137                 if (matchpathcon (dst_name, 0, &scontext) < 0) {
138                         if (security_getenforce () != 0) {
139                                 return 1;
140                         }
141                 }
142                 /* Set the security context for the next created file */
143                 if (setfscreatecon (scontext) < 0) {
144                         if (security_getenforce () != 0) {
145                                 return 1;
146                         }
147                 }
148                 freecon (scontext);
149         }
150         return 0;
151 }
152
153 /*
154  * reset_selinux_file_context - Reset the security context to the default
155  *                              policy behavior
156  *
157  *      reset_selinux_file_context () should be called after the context
158  *      was changed with set_selinux_file_context ()
159  */
160 int reset_selinux_file_context (void)
161 {
162         if (!selinux_checked) {
163                 selinux_enabled = is_selinux_enabled () > 0;
164                 selinux_checked = true;
165         }
166         if (selinux_enabled) {
167                 if (setfscreatecon (NULL) != 0) {
168                         return 1;
169                 }
170         }
171         return 0;
172 }
173 #endif                          /* WITH_SELINUX */
174
175 #if defined(WITH_ACL) || defined(WITH_ATTR)
176 /*
177  * error_acl - format the error messages for the ACL and EQ libraries.
178  */
179 static void error_acl (struct error_context *ctx, const char *fmt, ...)
180 {
181         va_list ap;
182
183         /* ignore the case when destination does not support ACLs 
184          * or extended attributes */
185         if (ENOTSUP == errno) {
186                 errno = 0;
187                 return;
188         }
189
190         va_start (ap, fmt);
191         (void) fprintf (stderr, _("%s: "), Prog);
192         if (vfprintf (stderr, fmt, ap) != 0) {
193                 (void) fputs (_(": "), stderr);
194         }
195         (void) fprintf (stderr, "%s\n", strerror (errno));
196         va_end (ap);
197 }
198
199 static struct error_context ctx = {
200         error_acl
201 };
202 #endif                          /* WITH_ACL || WITH_ATTR */
203
204 /*
205  * remove_link - delete a link from the linked list
206  */
207 static void remove_link (/*@only@*/struct link_name *ln)
208 {
209         struct link_name *lp;
210
211         if (links == ln) {
212                 links = ln->ln_next;
213                 free (ln->ln_name);
214                 free (ln);
215                 return;
216         }
217         for (lp = links; NULL !=lp; lp = lp->ln_next) {
218                 if (lp->ln_next == ln) {
219                         break;
220                 }
221         }
222
223         if (NULL == lp) {
224                 free (ln->ln_name);
225                 free (ln);
226                 return;
227         }
228
229         lp->ln_next = lp->ln_next->ln_next;
230         free (ln->ln_name);
231         free (ln);
232 }
233
234 /*
235  * check_link - see if a file is really a link
236  */
237
238 static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, const struct stat *sb)
239 {
240         struct link_name *lp;
241         size_t src_len;
242         size_t dst_len;
243         size_t name_len;
244         size_t len;
245
246         /* copy_tree () must be the entry point */
247         assert (NULL != src_orig);
248         assert (NULL != dst_orig);
249
250         for (lp = links; NULL != lp; lp = lp->ln_next) {
251                 if ((lp->ln_dev == sb->st_dev) && (lp->ln_ino == sb->st_ino)) {
252                         return lp;
253                 }
254         }
255
256         if (sb->st_nlink == 1) {
257                 return NULL;
258         }
259
260         lp = (struct link_name *) xmalloc (sizeof *lp);
261         src_len = strlen (src_orig);
262         dst_len = strlen (dst_orig);
263         name_len = strlen (name);
264         lp->ln_dev = sb->st_dev;
265         lp->ln_ino = sb->st_ino;
266         lp->ln_count = sb->st_nlink;
267         len = name_len - src_len + dst_len + 1;
268         lp->ln_name = (char *) xmalloc (len);
269         (void) snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
270         lp->ln_next = links;
271         links = lp;
272
273         return NULL;
274 }
275
276 /*
277  * copy_tree - copy files in a directory tree
278  *
279  *      copy_tree() walks a directory tree and copies ordinary files
280  *      as it goes.
281  *
282  *      When reset_selinux is enabled, extended attributes (and thus
283  *      SELinux attributes) are not copied.
284  *
285  *      old_uid and new_uid are used to set the ownership of the copied
286  *      files. Unless old_uid is set to -1, only the files owned by
287  *      old_uid have their ownership changed to new_uid. In addition, if
288  *      new_uid is set to -1, no ownership will be changed.
289  *
290  *      The same logic applies for the group-ownership and
291  *      old_gid/new_gid.
292  */
293 int copy_tree (const char *src_root, const char *dst_root,
294                bool copy_root, bool reset_selinux,
295                uid_t old_uid, uid_t new_uid,
296                gid_t old_gid, gid_t new_gid)
297 {
298         int err = 0;
299         bool set_orig = false;
300         struct DIRECT *ent;
301         DIR *dir;
302
303         if (copy_root) {
304                 struct stat sb;
305                 if (access (dst_root, F_OK) == 0) {
306                         return -1;
307                 }
308
309                 if (LSTAT (src_root, &sb) == -1) {
310                         return -1;
311                 }
312
313                 if (!S_ISDIR (sb.st_mode)) {
314                         fprintf (stderr,
315                                  "%s: %s is not a directory",
316                                  Prog, src_root);
317                         return -1;
318                 }
319
320                 return copy_entry (src_root, dst_root, reset_selinux,
321                                    old_uid, new_uid, old_gid, new_gid);
322         }
323
324         /*
325          * Make certain both directories exist.  This routine is called
326          * after the home directory is created, or recursively after the
327          * target is created.  It assumes the target directory exists.
328          */
329
330         if (   (access (src_root, F_OK) != 0)
331             || (access (dst_root, F_OK) != 0)) {
332                 return -1;
333         }
334
335         /*
336          * Open the source directory and read each entry.  Every file
337          * entry in the directory is copied with the UID and GID set
338          * to the provided values.  As an added security feature only
339          * regular files (and directories ...) are copied, and no file
340          * is made set-ID.
341          */
342         dir = opendir (src_root);
343         if (NULL == dir) {
344                 return -1;
345         }
346
347         if (src_orig == NULL) {
348                 src_orig = src_root;
349                 dst_orig = dst_root;
350                 set_orig = true;
351         }
352         while ((0 == err) && (ent = readdir (dir)) != NULL) {
353                 /*
354                  * Skip the "." and ".." entries
355                  */
356                 if ((strcmp (ent->d_name, ".") != 0) &&
357                     (strcmp (ent->d_name, "..") != 0)) {
358                         char *src_name;
359                         char *dst_name;
360                         size_t src_len = strlen (ent->d_name) + 2;
361                         size_t dst_len = strlen (ent->d_name) + 2;
362                         src_len += strlen (src_root);
363                         dst_len += strlen (dst_root);
364
365                         src_name = (char *) malloc (src_len);
366                         dst_name = (char *) malloc (dst_len);
367
368                         if ((NULL == src_name) || (NULL == dst_name)) {
369                                 err = -1;
370                         } else {
371                                 /*
372                                  * Build the filename for both the source and
373                                  * the destination files.
374                                  */
375                                 (void) snprintf (src_name, src_len, "%s/%s",
376                                                  src_root, ent->d_name);
377                                 (void) snprintf (dst_name, dst_len, "%s/%s",
378                                                  dst_root, ent->d_name);
379
380                                 err = copy_entry (src_name, dst_name,
381                                                   reset_selinux,
382                                                   old_uid, new_uid,
383                                                   old_gid, new_gid);
384                         }
385                         if (NULL != src_name) {
386                                 free (src_name);
387                         }
388                         if (NULL != dst_name) {
389                                 free (dst_name);
390                         }
391                 }
392         }
393         (void) closedir (dir);
394
395         if (set_orig) {
396                 src_orig = NULL;
397                 dst_orig = NULL;
398                 /* FIXME: clean links
399                  * Since there can be hardlinks elsewhere on the device,
400                  * we cannot check that all the hardlinks were found:
401                 assert (NULL == links);
402                  */
403         }
404
405 #ifdef WITH_SELINUX
406         /* Reset SELinux to create files with default contexts.
407          * Note that the context is only reset on exit of copy_tree (it is
408          * assumed that the program would quit without needing a restored
409          * context if copy_tree failed previously), and that copy_tree can
410          * be called recursively (hence the context is set on the
411          * sub-functions of copy_entry).
412          */
413         if (reset_selinux_file_context () != 0) {
414                 err = -1;
415         }
416 #endif                          /* WITH_SELINUX */
417
418         return err;
419 }
420
421 /*
422  * copy_entry - copy the entry of a directory
423  *
424  *      Copy the entry src to dst.
425  *      Depending on the type of entry, this function will forward the
426  *      request to copy_dir(), copy_symlink(), copy_hardlink(),
427  *      copy_special(), or copy_file().
428  *
429  *      The access and modification time will not be modified.
430  *
431  *      The permissions will be set to new_uid/new_gid.
432  *
433  *      If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
434  *      not be modified.
435  *
436  *      Only the files owned (resp. group-owned) by old_uid (resp.
437  *      old_gid) will be modified, unless old_uid (resp. old_gid) is set
438  *      to -1.
439  */
440 static int copy_entry (const char *src, const char *dst,
441                        bool reset_selinux,
442                        uid_t old_uid, uid_t new_uid,
443                        gid_t old_gid, gid_t new_gid)
444 {
445         int err = 0;
446         struct stat sb;
447         struct link_name *lp;
448         struct timeval mt[2];
449
450         if (LSTAT (src, &sb) == -1) {
451                 /* If we cannot stat the file, do not care. */
452         } else {
453 #ifdef HAVE_STRUCT_STAT_ST_ATIM
454                 mt[0].tv_sec  = sb.st_atim.tv_sec;
455                 mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
456 #else                           /* !HAVE_STRUCT_STAT_ST_ATIM */
457                 mt[0].tv_sec  = sb.st_atime;
458 # ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
459                 mt[0].tv_usec = sb.st_atimensec / 1000;
460 # else                          /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
461                 mt[0].tv_usec = 0;
462 # endif                         /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
463 #endif                          /* !HAVE_STRUCT_STAT_ST_ATIM */
464
465 #ifdef HAVE_STRUCT_STAT_ST_MTIM
466                 mt[1].tv_sec  = sb.st_mtim.tv_sec;
467                 mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
468 #else                           /* !HAVE_STRUCT_STAT_ST_MTIM */
469                 mt[1].tv_sec  = sb.st_mtime;
470 # ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
471                 mt[1].tv_usec = sb.st_mtimensec / 1000;
472 # else                          /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
473                 mt[1].tv_usec = 0;
474 # endif                         /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
475 #endif                          /* !HAVE_STRUCT_STAT_ST_MTIM */
476
477                 if (S_ISDIR (sb.st_mode)) {
478                         err = copy_dir (src, dst, reset_selinux, &sb, mt,
479                                         old_uid, new_uid, old_gid, new_gid);
480                 }
481
482 #ifdef  S_IFLNK
483                 /*
484                  * Copy any symbolic links
485                  */
486
487                 else if (S_ISLNK (sb.st_mode)) {
488                         err = copy_symlink (src, dst, reset_selinux, &sb, mt,
489                                             old_uid, new_uid, old_gid, new_gid);
490                 }
491 #endif                          /* S_IFLNK */
492
493                 /*
494                  * See if this is a previously copied link
495                  */
496
497                 else if ((lp = check_link (src, &sb)) != NULL) {
498                         err = copy_hardlink (dst, reset_selinux, lp);
499                 }
500
501                 /*
502                  * Deal with FIFOs and special files.  The user really
503                  * shouldn't have any of these, but it seems like it
504                  * would be nice to copy everything ...
505                  */
506
507                 else if (!S_ISREG (sb.st_mode)) {
508                         err = copy_special (src, dst, reset_selinux, &sb, mt,
509                                             old_uid, new_uid, old_gid, new_gid);
510                 }
511
512                 /*
513                  * Create the new file and copy the contents.  The new
514                  * file will be owned by the provided UID and GID values.
515                  */
516
517                 else {
518                         err = copy_file (src, dst, reset_selinux, &sb, mt,
519                                          old_uid, new_uid, old_gid, new_gid);
520                 }
521         }
522
523         return err;
524 }
525
526 /*
527  * copy_dir - copy a directory
528  *
529  *      Copy a directory (recursively) from src to dst.
530  *
531  *      statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
532  *      the access and modification and the access rights.
533  *
534  *      Return 0 on success, -1 on error.
535  */
536 static int copy_dir (const char *src, const char *dst,
537                      bool reset_selinux,
538                      const struct stat *statp, const struct timeval mt[],
539                      uid_t old_uid, uid_t new_uid,
540                      gid_t old_gid, gid_t new_gid)
541 {
542         int err = 0;
543
544         /*
545          * Create a new target directory, make it owned by
546          * the user and then recursively copy that directory.
547          */
548
549 #ifdef WITH_SELINUX
550         if (set_selinux_file_context (dst) != 0) {
551                 return -1;
552         }
553 #endif                          /* WITH_SELINUX */
554         if (   (mkdir (dst, statp->st_mode) != 0)
555             || (chown_if_needed (dst, statp,
556                                  old_uid, new_uid, old_gid, new_gid) != 0)
557 #ifdef WITH_ACL
558             || (   (perm_copy_file (src, dst, &ctx) != 0)
559                 && (errno != 0))
560 #else                           /* !WITH_ACL */
561             || (chmod (dst, statp->st_mode) != 0)
562 #endif                          /* !WITH_ACL */
563 #ifdef WITH_ATTR
564         /*
565          * If the third parameter is NULL, all extended attributes
566          * except those that define Access Control Lists are copied.
567          * ACLs are excluded by default because copying them between
568          * file systems with and without ACL support needs some
569          * additional logic so that no unexpected permissions result.
570          */
571             || (   !reset_selinux
572                 && (attr_copy_file (src, dst, NULL, &ctx) != 0)
573                 && (errno != 0))
574 #endif                          /* WITH_ATTR */
575             || (copy_tree (src, dst, false, reset_selinux,
576                            old_uid, new_uid, old_gid, new_gid) != 0)
577             || (utimes (dst, mt) != 0)) {
578                 err = -1;
579         }
580
581         return err;
582 }
583
584 #ifdef  S_IFLNK
585 /*
586  * readlink_malloc - wrapper for readlink
587  *
588  * return NULL on error.
589  * The return string shall be freed by the caller.
590  */
591 static /*@null@*/char *readlink_malloc (const char *filename)
592 {
593         size_t size = 1024;
594
595         while (true) {
596                 ssize_t nchars;
597                 char *buffer = (char *) malloc (size);
598                 if (NULL == buffer) {
599                         return NULL;
600                 }
601
602                 nchars = readlink (filename, buffer, size);
603
604                 if (nchars < 0) {
605                         free(buffer);
606                         return NULL;
607                 }
608
609                 if ((size_t) nchars < size) { /* The buffer was large enough */
610                         /* readlink does not nul-terminate */
611                         buffer[nchars] = '\0';
612                         return buffer;
613                 }
614
615                 /* Try again with a bigger buffer */
616                 free (buffer);
617                 size *= 2;
618         }
619 }
620
621 /*
622  * copy_symlink - copy a symlink
623  *
624  *      Copy a symlink from src to dst.
625  *
626  *      statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
627  *      the access and modification and the access rights.
628  *
629  *      Return 0 on success, -1 on error.
630  */
631 static int copy_symlink (const char *src, const char *dst,
632                          unused bool reset_selinux,
633                          const struct stat *statp, const struct timeval mt[],
634                          uid_t old_uid, uid_t new_uid,
635                          gid_t old_gid, gid_t new_gid)
636 {
637         char *oldlink;
638
639         /* copy_tree () must be the entry point */
640         assert (NULL != src_orig);
641         assert (NULL != dst_orig);
642
643         /*
644          * Get the name of the file which the link points
645          * to.  If that name begins with the original
646          * source directory name, that part of the link
647          * name will be replaced with the original
648          * destination directory name.
649          */
650
651         oldlink = readlink_malloc (src);
652         if (NULL == oldlink) {
653                 return -1;
654         }
655
656         /* If src was a link to an entry of the src_orig directory itself,
657          * create a link to the corresponding entry in the dst_orig
658          * directory.
659          */
660         if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
661                 size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
662                 char *dummy = (char *) xmalloc (len);
663                 (void) snprintf (dummy, len, "%s%s",
664                                  dst_orig,
665                                  oldlink + strlen (src_orig));
666                 free (oldlink);
667                 oldlink = dummy;
668         }
669
670 #ifdef WITH_SELINUX
671         if (set_selinux_file_context (dst) != 0) {
672                 free (oldlink);
673                 return -1;
674         }
675 #endif                          /* WITH_SELINUX */
676         if (   (symlink (oldlink, dst) != 0)
677             || (lchown_if_needed (dst, statp,
678                                   old_uid, new_uid, old_gid, new_gid) != 0)) {
679                 /* FIXME: there are no modes on symlinks, right?
680                  *        ACL could be copied, but this would be much more
681                  *        complex than calling perm_copy_file.
682                  *        Ditto for Extended Attributes.
683                  *        We currently only document that ACL and Extended
684                  *        Attributes are not copied.
685                  */
686                 free (oldlink);
687                 return -1;
688         }
689         free (oldlink);
690
691 #ifdef HAVE_LUTIMES
692         /* 2007-10-18: We don't care about
693          *  exit status of lutimes because
694          *  it returns ENOSYS on many system
695          *  - not implemented
696          */
697         (void) lutimes (dst, mt);
698 #endif                          /* HAVE_LUTIMES */
699
700         return 0;
701 }
702 #endif                          /* S_IFLNK */
703
704 /*
705  * copy_hardlink - copy a hardlink
706  *
707  *      Copy a hardlink from src to dst.
708  *
709  *      Return 0 on success, -1 on error.
710  */
711 static int copy_hardlink (const char *dst,
712                           unused bool reset_selinux,
713                           struct link_name *lp)
714 {
715         /* FIXME: selinux, ACL, Extended Attributes needed? */
716
717         if (link (lp->ln_name, dst) != 0) {
718                 return -1;
719         }
720
721         /* If the file could be unlinked, decrement the links counter,
722          * and forget about this link if it was the last reference */
723         lp->ln_count--;
724         if (lp->ln_count <= 0) {
725                 remove_link (lp);
726         }
727
728         return 0;
729 }
730
731 /*
732  * copy_special - copy a special file
733  *
734  *      Copy a special file from src to dst.
735  *
736  *      statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
737  *      the access and modification and the access rights.
738  *
739  *      Return 0 on success, -1 on error.
740  */
741 static int copy_special (const char *src, const char *dst,
742                          bool reset_selinux,
743                          const struct stat *statp, const struct timeval mt[],
744                          uid_t old_uid, uid_t new_uid,
745                          gid_t old_gid, gid_t new_gid)
746 {
747         int err = 0;
748
749 #ifdef WITH_SELINUX
750         if (set_selinux_file_context (dst) != 0) {
751                 return -1;
752         }
753 #endif                          /* WITH_SELINUX */
754
755         if (   (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
756             || (chown_if_needed (dst, statp,
757                                  old_uid, new_uid, old_gid, new_gid) != 0)
758 #ifdef WITH_ACL
759             || (   (perm_copy_file (src, dst, &ctx) != 0)
760                 && (errno != 0))
761 #else                           /* !WITH_ACL */
762             || (chmod (dst, statp->st_mode & 07777) != 0)
763 #endif                          /* !WITH_ACL */
764 #ifdef WITH_ATTR
765         /*
766          * If the third parameter is NULL, all extended attributes
767          * except those that define Access Control Lists are copied.
768          * ACLs are excluded by default because copying them between
769          * file systems with and without ACL support needs some
770          * additional logic so that no unexpected permissions result.
771          */
772             || (   !reset_selinux
773                 && (attr_copy_file (src, dst, NULL, &ctx) != 0)
774                 && (errno != 0))
775 #endif                          /* WITH_ATTR */
776             || (utimes (dst, mt) != 0)) {
777                 err = -1;
778         }
779
780         return err;
781 }
782
783 /*
784  * copy_file - copy a file
785  *
786  *      Copy a file from src to dst.
787  *
788  *      statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
789  *      the access and modification and the access rights.
790  *
791  *      Return 0 on success, -1 on error.
792  */
793 static int copy_file (const char *src, const char *dst,
794                       bool reset_selinux,
795                       const struct stat *statp, const struct timeval mt[],
796                       uid_t old_uid, uid_t new_uid,
797                       gid_t old_gid, gid_t new_gid)
798 {
799         int err = 0;
800         int ifd;
801         int ofd;
802         char buf[1024];
803         ssize_t cnt;
804
805         ifd = open (src, O_RDONLY);
806         if (ifd < 0) {
807                 return -1;
808         }
809 #ifdef WITH_SELINUX
810         if (set_selinux_file_context (dst) != 0) {
811                 return -1;
812         }
813 #endif                          /* WITH_SELINUX */
814         ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
815         if (   (ofd < 0)
816             || (fchown_if_needed (ofd, statp,
817                                   old_uid, new_uid, old_gid, new_gid) != 0)
818 #ifdef WITH_ACL
819             || (   (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
820                 && (errno != 0))
821 #else                           /* !WITH_ACL */
822             || (fchmod (ofd, statp->st_mode & 07777) != 0)
823 #endif                          /* !WITH_ACL */
824 #ifdef WITH_ATTR
825         /*
826          * If the third parameter is NULL, all extended attributes
827          * except those that define Access Control Lists are copied.
828          * ACLs are excluded by default because copying them between
829          * file systems with and without ACL support needs some
830          * additional logic so that no unexpected permissions result.
831          */
832             || (   !reset_selinux
833                 && (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
834                 && (errno != 0))
835 #endif                          /* WITH_ATTR */
836            ) {
837                 (void) close (ifd);
838                 return -1;
839         }
840
841         while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
842                 if (write (ofd, buf, (size_t)cnt) != cnt) {
843                         (void) close (ifd);
844                         return -1;
845                 }
846         }
847
848         (void) close (ifd);
849
850 #ifdef HAVE_FUTIMES
851         if (futimes (ofd, mt) != 0) {
852                 return -1;
853         }
854 #endif                          /* HAVE_FUTIMES */
855
856         if (close (ofd) != 0) {
857                 return -1;
858         }
859
860 #ifndef HAVE_FUTIMES
861         if (utimes(dst, mt) != 0) {
862                 return -1;
863         }
864 #endif                          /* !HAVE_FUTIMES */
865
866         return err;
867 }
868
869 #define def_chown_if_needed(chown_function, type_dst)                  \
870 static int chown_function ## _if_needed (type_dst dst,                 \
871                                          const struct stat *statp,     \
872                                          uid_t old_uid, uid_t new_uid, \
873                                          gid_t old_gid, gid_t new_gid) \
874 {                                                                      \
875         uid_t tmpuid = (uid_t) -1;                                     \
876         gid_t tmpgid = (gid_t) -1;                                     \
877                                                                        \
878         /* Use new_uid if old_uid is set to -1 or if the file was      \
879          * owned by the user. */                                       \
880         if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) {   \
881                 tmpuid = new_uid;                                      \
882         }                                                              \
883         /* Otherwise, or if new_uid was set to -1, we keep the same    \
884          * owner. */                                                   \
885         if ((uid_t) -1 == tmpuid) {                                    \
886                 tmpuid = statp->st_uid;                                \
887         }                                                              \
888                                                                        \
889         if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) {   \
890                 tmpgid = new_gid;                                      \
891         }                                                              \
892         if ((gid_t) -1 == tmpgid) {                                    \
893                 tmpgid = statp->st_gid;                                \
894         }                                                              \
895                                                                        \
896         return chown_function (dst, tmpuid, tmpgid);                   \
897 }
898
899 def_chown_if_needed (chown, const char *)
900 def_chown_if_needed (lchown, const char *)
901 def_chown_if_needed (fchown, int)
902