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 - 2008, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
39 #include <sys/types.h>
43 #include "prototypes.h"
46 #include <selinux/selinux.h>
48 static /*@null@*/const char *src_orig;
49 static /*@null@*/const char *dst_orig;
56 /*@dependent@*/struct link_name *ln_next;
58 static /*@exposed@*/struct link_name *links;
60 static int copy_entry (const char *src, const char *dst,
61 long int uid, long int gid);
62 static int copy_dir (const char *src, const char *dst,
63 const struct stat *statp, const struct timeval mt[],
64 long int uid, long int gid);
66 static char *readlink_malloc (const char *filename);
67 static int copy_symlink (const char *src, const char *dst,
68 const struct stat *statp, const struct timeval mt[],
69 long int uid, long int gid);
71 static int copy_hardlink (const char *src, const char *dst,
72 struct link_name *lp);
73 static int copy_special (const char *dst,
74 const struct stat *statp, const struct timeval mt[],
75 long int uid, long int gid);
76 static int copy_file (const char *src, const char *dst,
77 const struct stat *statp, const struct timeval mt[],
78 long int uid, long int gid);
82 * selinux_file_context - Set the security context before any file or
85 * selinux_file_context () should be called before any creation of file,
86 * symlink, directory, ...
88 * Callers may have to Reset SELinux to create files with default
90 * setfscreatecon (NULL);
92 int selinux_file_context (const char *dst_name)
94 static bool selinux_checked = false;
95 static bool selinux_enabled;
96 security_context_t scontext = NULL;
98 if (!selinux_checked) {
99 selinux_enabled = is_selinux_enabled () > 0;
100 selinux_checked = true;
103 if (selinux_enabled) {
104 /* Get the default security context for this file */
105 if (matchpathcon (dst_name, 0, &scontext) < 0) {
106 if (security_getenforce () != 0) {
110 /* Set the security context for the next created file */
111 if (setfscreatecon (scontext) < 0) {
112 if (security_getenforce () != 0) {
123 * remove_link - delete a link from the linked list
125 static void remove_link (/*@only@*/struct link_name *ln)
127 struct link_name *lp;
135 for (lp = links; NULL !=lp; lp = lp->ln_next) {
136 if (lp->ln_next == ln) {
147 lp->ln_next = lp->ln_next->ln_next;
153 * check_link - see if a file is really a link
156 static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, const struct stat *sb)
158 struct link_name *lp;
164 /* copy_tree () must be the entry point */
165 assert (NULL != src_orig);
166 assert (NULL != dst_orig);
168 for (lp = links; NULL != lp; lp = lp->ln_next) {
169 if ((lp->ln_dev == sb->st_dev) && (lp->ln_ino == sb->st_ino)) {
174 if (sb->st_nlink == 1) {
178 lp = (struct link_name *) xmalloc (sizeof *lp);
179 src_len = strlen (src_orig);
180 dst_len = strlen (dst_orig);
181 name_len = strlen (name);
182 lp->ln_dev = sb->st_dev;
183 lp->ln_ino = sb->st_ino;
184 lp->ln_count = sb->st_nlink;
185 len = name_len - src_len + dst_len + 1;
186 lp->ln_name = (char *) xmalloc (len);
187 snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
195 * copy_tree - copy files in a directory tree
197 * copy_tree() walks a directory tree and copies ordinary files
200 int copy_tree (const char *src_root, const char *dst_root,
201 long int uid, long int gid)
204 bool set_orig = false;
209 * Make certain both directories exist. This routine is called
210 * after the home directory is created, or recursively after the
211 * target is created. It assumes the target directory exists.
214 if ( (access (src_root, F_OK) != 0)
215 || (access (dst_root, F_OK) != 0)) {
220 * Open the source directory and read each entry. Every file
221 * entry in the directory is copied with the UID and GID set
222 * to the provided values. As an added security feature only
223 * regular files (and directories ...) are copied, and no file
226 dir = opendir (src_root);
231 if (src_orig == NULL) {
236 while ((0 == err) && (ent = readdir (dir)) != NULL) {
238 * Skip the "." and ".." entries
240 if ((strcmp (ent->d_name, ".") != 0) &&
241 (strcmp (ent->d_name, "..") != 0)) {
244 size_t src_len = strlen (ent->d_name) + 2;
245 size_t dst_len = strlen (ent->d_name) + 2;
246 src_len += strlen (src_root);
247 dst_len += strlen (dst_root);
249 src_name = (char *) malloc (src_len);
250 dst_name = (char *) malloc (dst_len);
252 if ((NULL == src_name) || (NULL == dst_name)) {
256 * Build the filename for both the source and
257 * the destination files.
259 snprintf (src_name, src_len, "%s/%s",
260 src_root, ent->d_name);
261 snprintf (dst_name, dst_len, "%s/%s",
262 dst_root, ent->d_name);
264 err = copy_entry (src_name, dst_name, uid, gid);
266 if (NULL != src_name) {
269 if (NULL != dst_name) {
274 (void) closedir (dir);
282 /* Reset SELinux to create files with default contexts */
283 setfscreatecon (NULL);
286 /* FIXME: with the call to remove_link, we could also check that
287 * no links remain in links.
288 * assert (NULL == links); */
294 * copy_entry - copy the entry of a directory
296 * Copy the entry src to dst.
297 * Depending on the type of entry, this function will forward the
298 * request to copy_dir(), copy_symlink(), copy_hardlink(),
299 * copy_special(), or copy_file().
301 * The access and modification time will not be modified.
303 * The permissions will be set to uid/gid.
305 * If uid (resp. gid) is equal to -1, the user (resp. group) will
308 static int copy_entry (const char *src, const char *dst,
309 long int uid, long int gid)
313 struct link_name *lp;
314 struct timeval mt[2];
316 if (LSTAT (src, &sb) == -1) {
317 /* If we cannot stat the file, do not care. */
319 #ifdef HAVE_STRUCT_STAT_ST_ATIM
320 mt[0].tv_sec = sb.st_atim.tv_sec;
321 mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
323 mt[0].tv_sec = sb.st_atime;
324 #ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
325 mt[0].tv_usec = sb.st_atimensec / 1000;
331 #ifdef HAVE_STRUCT_STAT_ST_MTIM
332 mt[1].tv_sec = sb.st_mtim.tv_sec;
333 mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
335 mt[1].tv_sec = sb.st_mtime;
336 #ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
337 mt[1].tv_usec = sb.st_mtimensec / 1000;
343 if (S_ISDIR (sb.st_mode)) {
344 err = copy_dir (src, dst, &sb, mt, uid, gid);
349 * Copy any symbolic links
352 else if (S_ISLNK (sb.st_mode)) {
353 err = copy_symlink (src, dst, &sb, mt, uid, gid);
358 * See if this is a previously copied link
361 else if ((lp = check_link (src, &sb)) != NULL) {
362 err = copy_hardlink (src, dst, lp);
366 * Deal with FIFOs and special files. The user really
367 * shouldn't have any of these, but it seems like it
368 * would be nice to copy everything ...
371 else if (!S_ISREG (sb.st_mode)) {
372 err = copy_special (dst, &sb, mt, uid, gid);
376 * Create the new file and copy the contents. The new
377 * file will be owned by the provided UID and GID values.
381 err = copy_file (src, dst, &sb, mt, uid, gid);
389 * copy_dir - copy a directory
391 * Copy a directory (recursively) from src to dst.
393 * statp, mt, uid, gid are used to set the access and modification and the
396 * Return 0 on success, -1 on error.
398 static int copy_dir (const char *src, const char *dst,
399 const struct stat *statp, const struct timeval mt[],
400 long int uid, long int gid)
405 * Create a new target directory, make it owned by
406 * the user and then recursively copy that directory.
410 selinux_file_context (dst);
412 if ( (mkdir (dst, statp->st_mode) != 0)
414 (uid == - 1) ? statp->st_uid : (uid_t) uid,
415 (gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
416 || (chmod (dst, statp->st_mode) != 0)
417 || (copy_tree (src, dst, uid, gid) != 0)
418 || (utimes (dst, mt) != 0)) {
427 * readlink_malloc - wrapper for readlink
429 * return NULL on error.
430 * The return string shall be freed by the caller.
432 static char *readlink_malloc (const char *filename)
438 char *buffer = (char *) malloc (size);
439 if (NULL == buffer) {
443 nchars = readlink (filename, buffer, size);
450 if ( (size_t) nchars < size) { /* The buffer was large enough */
451 /* readlink does not nul-terminate */
452 buffer[nchars] = '\0';
456 /* Try again with a bigger buffer */
463 * copy_symlink - copy a symlink
465 * Copy a symlink from src to dst.
467 * statp, mt, uid, gid are used to set the access and modification and the
470 * Return 0 on success, -1 on error.
472 static int copy_symlink (const char *src, const char *dst,
473 const struct stat *statp, const struct timeval mt[],
474 long int uid, long int gid)
478 /* copy_tree () must be the entry point */
479 assert (NULL != src_orig);
480 assert (NULL != dst_orig);
483 * Get the name of the file which the link points
484 * to. If that name begins with the original
485 * source directory name, that part of the link
486 * name will be replaced with the original
487 * destination directory name.
490 oldlink = readlink_malloc (src);
491 if (NULL == oldlink) {
495 /* If src was a link to an entry of the src_orig directory itself,
496 * create a link to the corresponding entry in the dst_orig
498 * FIXME: This may change a relative link to an absolute link
500 if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
501 size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
502 char *dummy = (char *) malloc (len);
503 snprintf (dummy, len, "%s%s",
505 oldlink + strlen (src_orig));
511 selinux_file_context (dst);
513 if ( (symlink (oldlink, dst) != 0)
515 (uid == -1) ? statp->st_uid : (uid_t) uid,
516 (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
523 /* 2007-10-18: We don't care about
524 * exit status of lutimes because
525 * it returns ENOSYS on many system
536 * copy_hardlink - copy a hardlink
538 * Copy a hardlink from src to dst.
540 * Return 0 on success, -1 on error.
542 static int copy_hardlink (const char *src, const char *dst,
543 struct link_name *lp)
545 /* TODO: selinux needed? */
547 if (link (lp->ln_name, dst) != 0) {
551 /* FIXME: why is it unlinked? This is a copy, not a move */
552 if (unlink (src) != 0) {
556 /* FIXME: idem, although it may never be used again */
557 /* If the file could be unlinked, decrement the links counter,
558 * and delete the file if it was the last reference */
560 if (lp->ln_count <= 0) {
568 * copy_special - copy a special file
570 * Copy a special file from src to dst.
572 * statp, mt, uid, gid are used to set the access and modification and the
575 * Return 0 on success, -1 on error.
577 static int copy_special (const char *dst,
578 const struct stat *statp, const struct timeval mt[],
579 long int uid, long int gid)
584 selinux_file_context (dst);
587 if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
589 (uid == -1) ? statp->st_uid : (uid_t) uid,
590 (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
591 || (chmod (dst, statp->st_mode & 07777) != 0)
592 || (utimes (dst, mt) != 0)) {
600 * copy_file - copy a file
602 * Copy a file from src to dst.
604 * statp, mt, uid, gid are used to set the access and modification and the
607 * Return 0 on success, -1 on error.
609 static int copy_file (const char *src, const char *dst,
610 const struct stat *statp, const struct timeval mt[],
611 long int uid, long int gid)
619 ifd = open (src, O_RDONLY);
624 selinux_file_context (dst);
626 ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
629 (uid == -1) ? statp->st_uid : (uid_t) uid,
630 (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
631 || (fchmod (ofd, statp->st_mode & 07777) != 0)) {
636 while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
637 if (write (ofd, buf, (size_t)cnt) != cnt) {
645 if (futimes (ofd, mt) != 0) {
650 if (close (ofd) != 0) {
655 if (utimes(dst, mt) != 0) {
664 * remove_tree - delete a directory tree
666 * remove_tree() walks a directory tree and deletes all the files
668 * At the end, it deletes the root directory itself.
671 int remove_tree (const char *root)
673 char *new_name = NULL;
680 * Open the source directory and read each entry. Every file
681 * entry in the directory is copied with the UID and GID set
682 * to the provided values. As an added security feature only
683 * regular files (and directories ...) are copied, and no file
686 dir = opendir (root);
691 while ((ent = readdir (dir))) {
692 size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
695 * Skip the "." and ".." entries
698 if (strcmp (ent->d_name, ".") == 0 ||
699 strcmp (ent->d_name, "..") == 0) {
704 * Make the filename for the current entry.
707 if (NULL != new_name) {
710 new_name = (char *) malloc (new_len);
711 if (NULL == new_name) {
715 snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
716 if (LSTAT (new_name, &sb) == -1) {
720 if (S_ISDIR (sb.st_mode)) {
722 * Recursively delete this directory.
724 if (remove_tree (new_name) != 0) {
732 if (unlink (new_name) != 0) {
738 if (NULL != new_name) {
741 (void) closedir (dir);
744 if (rmdir (root) != 0) {