Exemplo n.º 1
0
int
file_creat(ARCHD *arcn)
{
    int fd = -1;
    mode_t file_mode;
    int oerrno;

    /*
     * assume file doesn't exist, so just try to create it, most times this
     * works. We have to take special handling when the file does exist. To
     * detect this, we use O_EXCL. For example when trying to create a
     * file and a character device or fifo exists with the same name, we
     * can accidently open the device by mistake (or block waiting to open)
     * If we find that the open has failed, then figure spend the effort to
     * figure out why. This strategy was found to have better average
     * performance in common use than checking the file (and the path)
     * first with lstat.
     */
    file_mode = arcn->sb.st_mode & FILEBITS;
    if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
                   file_mode)) >= 0)
        return(fd);

    /*
     * the file seems to exist. First we try to get rid of it (found to be
     * the second most common failure when traced). If this fails, only
     * then we go to the expense to check and create the path to the file
     */
    if (unlnk_exist(arcn->name, arcn->type) != 0)
        return(-1);

    for (;;) {
        /*
         * try to open it again, if this fails, check all the nodes in
         * the path and give it a final try. if chk_path() finds that
         * it cannot fix anything, we will skip the last attempt
         */
        if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC,
                       file_mode)) >= 0)
            break;
        oerrno = errno;
        if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
            syswarn(1, oerrno, "Unable to create %s", arcn->name);
            return(-1);
        }
    }
    return(fd);
}
Exemplo n.º 2
0
int
node_creat(ARCHD *arcn)
{
    int res;
    int ign = 0;
    int oerrno;
    int pass = 0;
    mode_t file_mode;
    struct stat sb;

    /*
     * create node based on type, if that fails try to unlink the node and
     * try again. finally check the path and try again. As noted in the
     * file and link creation routines, this method seems to exhibit the
     * best performance in general use workloads.
     */
    file_mode = arcn->sb.st_mode & FILEBITS;

    for (;;) {
        switch(arcn->type) {
        case PAX_DIR:
            res = mkdir(arcn->name, file_mode);
            if (ign)
                res = 0;
            break;
        case PAX_CHR:
            file_mode |= S_IFCHR;
            res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);
            break;
        case PAX_BLK:
            file_mode |= S_IFBLK;
            res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);
            break;
        case PAX_FIF:
            res = mkfifo(arcn->name, file_mode);
            break;
        case PAX_SCK:
            /*
             * Skip sockets, operation has no meaning under BSD
             */
            paxwarn(0,
                    "%s skipped. Sockets cannot be copied or extracted",
                    arcn->name);
            return(-1);
        case PAX_SLK:
            res = symlink(arcn->ln_name, arcn->name);
            break;
        case PAX_CTG:
        case PAX_HLK:
        case PAX_HRG:
        case PAX_REG:
        default:
            /*
             * we should never get here
             */
            paxwarn(0, "%s has an unknown file type, skipping",
                    arcn->name);
            return(-1);
        }

        /*
         * if we were able to create the node break out of the loop,
         * otherwise try to unlink the node and try again. if that
         * fails check the full path and try a final time.
         */
        if (res == 0)
            break;

        /*
         * we failed to make the node
         */
        oerrno = errno;
        if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0)
            return(-1);

        if (++pass <= 1)
            continue;

        if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
            syswarn(1, oerrno, "Could not create: %s", arcn->name);
            return(-1);
        }
    }

    /*
     * we were able to create the node. set uid/gid, modes and times
     */
    if (pids)
        res = ((arcn->type == PAX_SLK) ?
               set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) :
               set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid));
    else
        res = 0;

    /*
     * symlinks are done now.
     */
    if (arcn->type == PAX_SLK)
        return(0);

    /*
     * IMPORTANT SECURITY NOTE:
     * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
     * set uid/gid bits
     */
    if (!pmode || res)
        arcn->sb.st_mode &= ~(SETBITS);
    if (pmode)
        set_pmode(arcn->name, arcn->sb.st_mode);

    if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
        /*
         * Dirs must be processed again at end of extract to set times
         * and modes to agree with those stored in the archive. However
         * to allow extract to continue, we may have to also set owner
         * rights. This allows nodes in the archive that are children
         * of this directory to be extracted without failure. Both time
         * and modes will be fixed after the entire archive is read and
         * before pax exits.
         */
        if (access(arcn->name, R_OK | W_OK | X_OK) < 0) {
            if (lstat(arcn->name, &sb) < 0) {
                syswarn(0, errno,"Could not access %s (stat)",
                        arcn->name);
                set_pmode(arcn->name,file_mode | S_IRWXU);
            } else {
                /*
                 * We have to add rights to the dir, so we make
                 * sure to restore the mode. The mode must be
                 * restored AS CREATED and not as stored if
                 * pmode is not set.
                 */
                set_pmode(arcn->name,
                          ((sb.st_mode & FILEBITS) | S_IRWXU));
                if (!pmode)
                    arcn->sb.st_mode = sb.st_mode;
            }

            /*
             * we have to force the mode to what was set here,
             * since we changed it from the default as created.
             */
            add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1);
        } else if (pmode || patime || pmtime)
            add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0);
    }

    if (patime || pmtime)
        set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
    return(0);
}
Exemplo n.º 3
0
static int
mk_link(char *to, struct stat *to_sb, char *from,
        int ign)
{
    struct stat sb;
    int oerrno;

    /*
     * if from file exists, it has to be unlinked to make the link. If the
     * file exists and -k is set, skip it quietly
     */
    if (lstat(from, &sb) == 0) {
        if (kflag)
            return(0);

        /*
         * make sure it is not the same file, protect the user
         */
        if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {
            paxwarn(1, "Unable to link file %s to itself", to);
            return(-1);;
        }

        /*
         * try to get rid of the file, based on the type
         */
        if (S_ISDIR(sb.st_mode)) {
            if (rmdir(from) < 0) {
                syswarn(1, errno, "Unable to remove %s", from);
                return(-1);
            }
        } else if (unlink(from) < 0) {
            if (!ign) {
                syswarn(1, errno, "Unable to remove %s", from);
                return(-1);
            }
            return(1);
        }
    }

    /*
     * from file is gone (or did not exist), try to make the hard link.
     * if it fails, check the path and try it again (if chk_path() says to
     * try again)
     */
    for (;;) {
        if (link(to, from) == 0)
            break;
        oerrno = errno;
        if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0)
            continue;
        if (!ign) {
            syswarn(1, oerrno, "Could not link to %s from %s", to,
                    from);
            return(-1);
        }
        return(1);
    }

    /*
     * all right the link was made
     */
    return(0);
}
Exemplo n.º 4
0
int
node_creat(ARCHD *arcn)
{
	int res;
	int ign = 0;
	int oerrno;
	int pass = 0;
	mode_t file_mode;
	struct stat sb;
	char target[MAXPATHLEN];
	char *nm = arcn->name;
	int len;

	/*
	 * create node based on type, if that fails try to unlink the node and
	 * try again. finally check the path and try again. As noted in the
	 * file and link creation routines, this method seems to exhibit the
	 * best performance in general use workloads.
	 */
	file_mode = arcn->sb.st_mode & FILEBITS(arcn->type == PAX_DIR);

	for (;;) {
		switch (arcn->type) {
		case PAX_DIR:
			/*
			 * If -h (or -L) was given in tar-mode, follow the
			 * potential symlink chain before trying to create the
			 * directory.
			 */
			if (strcmp(NM_TAR, argv0) == 0 && Lflag) {
				while (lstat(nm, &sb) == 0 &&
				    S_ISLNK(sb.st_mode)) {
					len = readlink(nm, target,
					    sizeof target - 1);
					if (len == -1) {
						syswarn(0, errno,
						   "cannot follow symlink %s "
						   "in chain for %s",
						    nm, arcn->name);
						res = -1;
						goto badlink;
					}
					target[len] = '\0';
					nm = target;
				}
			}
			res = domkdir(nm, file_mode);
badlink:
			if (ign)
				res = 0;
			break;
		case PAX_CHR:
			file_mode |= S_IFCHR;
			res = mknod(nm, file_mode, arcn->sb.st_rdev);
			break;
		case PAX_BLK:
			file_mode |= S_IFBLK;
			res = mknod(nm, file_mode, arcn->sb.st_rdev);
			break;
		case PAX_FIF:
			res = mkfifo(nm, file_mode);
			break;
		case PAX_SCK:
			/*
			 * Skip sockets, operation has no meaning under BSD
			 */
			tty_warn(0,
			    "%s skipped. Sockets cannot be copied or extracted",
			    nm);
			return (-1);
		case PAX_SLK:
			res = symlink(arcn->ln_name, nm);
			break;
		case PAX_CTG:
		case PAX_HLK:
		case PAX_HRG:
		case PAX_REG:
		default:
			/*
			 * we should never get here
			 */
			tty_warn(0, "%s has an unknown file type, skipping",
			    nm);
			return (-1);
		}

		/*
		 * if we were able to create the node break out of the loop,
		 * otherwise try to unlink the node and try again. if that
		 * fails check the full path and try a final time.
		 */
		if (res == 0)
			break;

		/*
		 * we failed to make the node
		 */
		oerrno = errno;
		switch (pass++) {
		case 0:
			if ((ign = unlnk_exist(nm, arcn->type)) < 0)
				return (-1);
			continue;

		case 1:
			if (nodirs ||
			    chk_path(nm, arcn->sb.st_uid,
			    arcn->sb.st_gid) < 0) {
				syswarn(1, oerrno, "Cannot create %s", nm);
				return (-1);
			}
			continue;
		}

		/*
		 * it must be a file that exists but we can't create or
		 * remove, but we must avoid the infinite loop.
		 */
		break;
	}

	/*
	 * we were able to create the node. set uid/gid, modes and times
	 */
	if (pids)
		res = set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid);
	else
		res = 0;

	/*
	 * IMPORTANT SECURITY NOTE:
	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
	 * set uid/gid bits
	 */
	if (!pmode || res)
		arcn->sb.st_mode &= ~SETBITS(arcn->type == PAX_DIR);
	if (pmode)
		set_pmode(arcn->name, arcn->sb.st_mode);

	if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
		/*
		 * Dirs must be processed again at end of extract to set times
		 * and modes to agree with those stored in the archive. However
		 * to allow extract to continue, we may have to also set owner
		 * rights. This allows nodes in the archive that are children
		 * of this directory to be extracted without failure. Both time
		 * and modes will be fixed after the entire archive is read and
		 * before pax exits.
		 */
		if (access(nm, R_OK | W_OK | X_OK) < 0) {
			if (lstat(nm, &sb) < 0) {
				syswarn(0, errno,"Cannot access %s (stat)",
				    arcn->name);
				set_pmode(nm,file_mode | S_IRWXU);
			} else {
				/*
				 * We have to add rights to the dir, so we make
				 * sure to restore the mode. The mode must be
				 * restored AS CREATED and not as stored if
				 * pmode is not set.
				 */
				set_pmode(nm, ((sb.st_mode &
				    FILEBITS(arcn->type == PAX_DIR)) |
				    S_IRWXU));
				if (!pmode)
					arcn->sb.st_mode = sb.st_mode;
			}

			/*
			 * we have to force the mode to what was set here,
			 * since we changed it from the default as created.
			 */
			add_dir(nm, arcn->nlen, &(arcn->sb), 1);
		} else if (pmode || patime || pmtime)
			add_dir(nm, arcn->nlen, &(arcn->sb), 0);
	}

	if (patime || pmtime)
		set_ftime(arcn->name, arcn->sb.st_mtime,
		    arcn->sb.st_atime, 0, (arcn->type == PAX_SLK) ? 1 : 0);

#if HAVE_STRUCT_STAT_ST_FLAGS
	if (pfflags && arcn->type != PAX_SLK)
		set_chflags(arcn->name, arcn->sb.st_flags);
#endif
	return 0;
}
Exemplo n.º 5
0
int
file_creat(ARCHD *arcn, int write_to_hardlink)
{
	int fd = -1;
	int oerrno;

	/*
	 * Some horribly busted tar implementations, have directory nodes
	 * that end in a /, but they mark as files. Compensate for that
	 * by not creating a directory node at this point, but a file node,
	 * and not creating the temp file.
	 */
	if (arcn->nlen != 0 && arcn->name[arcn->nlen - 1] == '/') {
		if (!warn_broken) {
			tty_warn(0, "Archive was created with a broken tar;"
			    " file `%s' is a directory, but marked as plain.",
			    arcn->name);
			warn_broken = 1;
		}
		return -1;
	}

	/*
	 * In "cpio" archives it's usually the last record of a set of
	 * hardlinks which includes the contents of the file. We cannot
	 * use a tempory file in that case because we couldn't link it
	 * with the existing other hardlinks after restoring the contents
	 * to it. And it's also useless to create the hardlink under a
	 * temporary name because the other hardlinks would have partial
	 * contents while restoring.
	 */
	if (write_to_hardlink)
		return (open(arcn->name, O_TRUNC | O_EXCL | O_RDWR, 0));
	
	/*
	 * Create a temporary file name so that the file doesn't have partial
	 * contents while restoring.
	 */
	arcn->tmp_name = malloc(arcn->nlen + 8);
	if (arcn->tmp_name == NULL) {
		syswarn(1, errno, "Cannot malloc %d bytes", arcn->nlen + 8);
		return -1;
	}
	if (xtmp_name != NULL)
		abort();
	xtmp_name = arcn->tmp_name;

	for (;;) {
		/*
		 * try to create the temporary file we use to restore the
		 * contents info.  if this fails, keep checking all the nodes
		 * in the path until chk_path() finds that it cannot fix
		 * anything further.  if that happens we just give up.
		 */
		(void)snprintf(arcn->tmp_name, arcn->nlen + 8, "%s.XXXXXX",
		    arcn->name);
		fd = mkstemp(arcn->tmp_name);
		if (fd >= 0)
			break;
		oerrno = errno;
		if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
			(void)fflush(listf);
			syswarn(1, oerrno, "Cannot create %s", arcn->tmp_name);
			xtmp_name = NULL;
			free(arcn->tmp_name);
			arcn->tmp_name = NULL;
			return -1;
		}
	}
	return fd;
}
Exemplo n.º 6
0
int
file_creat(ARCHD *arcn)
{
    int fd = -1;
    mode_t file_mode;
    int oerrno;
    int rc = 0;
    char *path_to_open;
    char *new_path;
    char *cwd;
    char cwd_buff[MAXPATHLEN];

    /*
     * Assume file doesn't exist, so just try to create it, most times this
     * works. We have to take special handling when the file does exist. To
     * detect this, we use O_EXCL. For example when trying to create a
     * file and a character device or fifo exists with the same name, we
     * can accidently open the device by mistake (or block waiting to open).
     * If we find that the open has failed, then spend the effort to
     * figure out why. This strategy was found to have better average
     * performance in common use than checking the file (and the path)
     * first with lstat.
     */
    file_mode = arcn->sb.st_mode & FILEBITS;
    if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
                   file_mode)) >= 0)
        return(fd);

    /*
     * the file seems to exist. First we try to get rid of it (found to be
     * the second most common failure when traced). If this fails, only
     * then we go to the expense to check and create the path to the file
     */
    if (unlnk_exist(arcn->name, arcn->type) != 0)
        return(-1);

    path_to_open = arcn->name;
    new_path = arcn->name;
    cwd = getcwd(&cwd_buff[0],MAXPATHLEN);
    if (cwd==NULL) return -1;
    for (;;) {
        /*
         * try to open it again, if this fails, check all the nodes in
         * the path and give it a final try. if chk_path() finds that
         * it cannot fix anything, we will skip the last attempt
         */
        if ((fd = open(path_to_open, O_WRONLY | O_CREAT | O_TRUNC,
                       file_mode)) >= 0) {
            /* clean up the invalid_action */
            if (pax_invalid_action>0) {
                record_pax_invalid_action_results(arcn, path_to_open);
            }
            break;
        }
        oerrno = errno;
        if (pax_invalid_action>0) {
            rc = perform_pax_invalid_action(arcn, oerrno);
            if (rc == 0) continue;
            if (rc == 1) {
                fd = -1;
                break;
            }
        }
        /* rc == 2 reserved for -o invalid_action=write */
        if (nodirs || chk_path(path_to_open,arcn->sb.st_uid,arcn->sb.st_gid,
                               (rc==2) ? &new_path: NULL) < 0) {
            syswarn((pax_invalid_action==0), oerrno, "Unable to create %s", arcn->name);
            fd = -1;
            break;
        }
        if (new_path) path_to_open = new_path; /* try again */
    }
    if (strcmp(new_path, arcn->name)!=0) {
        dochdir(cwd);	/* go back to original directory */
    }
    return(fd);
}
Exemplo n.º 7
0
int
node_creat(ARCHD *arcn)
{
    int res;
    int ign = 0;
    int oerrno;
    int pass = 0;
    mode_t file_mode;
    struct stat sb;
    char target[MAXPATHLEN];
    char *nm = arcn->name;
    int nmlen = arcn->nlen;
    int len;

    /*
     * create node based on type, if that fails try to unlink the node and
     * try again. finally check the path and try again. As noted in the
     * file and link creation routines, this method seems to exhibit the
     * best performance in general use workloads.
     */
    file_mode = arcn->sb.st_mode & FILEBITS;

    for (;;) {
        switch (arcn->type) {
        case PAX_DIR:
            /*
             * If -h (or -L) was given in tar-mode, follow the
             * potential symlink chain before trying to create the
             * directory.
             */
            if (strcmp(NM_TAR, argv0) == 0 && Lflag) {
                while (lstat(nm, &sb) == 0 &&
                        S_ISLNK(sb.st_mode)) {
                    len = readlink(nm, target,
                                   sizeof target - 1);
                    if (len == -1) {
                        syswarn(0, errno,
                                "cannot follow symlink %s in chain for %s",
                                nm, arcn->name);
                        res = -1;
                        goto badlink;
                    }
                    target[len] = '\0';
                    nm = target;
                    nmlen = len;
                }
            }
            res = mkdir(nm, file_mode);

badlink:
            if (ign)
                res = 0;
            break;
        case PAX_CHR:
            file_mode |= S_IFCHR;
            res = mknod(nm, file_mode, arcn->sb.st_rdev);
            break;
        case PAX_BLK:
            file_mode |= S_IFBLK;
            res = mknod(nm, file_mode, arcn->sb.st_rdev);
            break;
        case PAX_FIF:
            res = mkfifo(nm, file_mode);
            break;
        case PAX_SCK:
            /*
             * Skip sockets, operation has no meaning under BSD
             */
            paxwarn(0,
                    "%s skipped. Sockets cannot be copied or extracted",
                    nm);
            return(-1);
        case PAX_SLK:
            res = symlink(arcn->ln_name, nm);
            break;
        case PAX_CTG:
        case PAX_HLK:
        case PAX_HRG:
        case PAX_REG:
        default:
            /*
             * we should never get here
             */
            paxwarn(0, "%s has an unknown file type, skipping",
                    nm);
            return(-1);
        }

        /*
         * if we were able to create the node break out of the loop,
         * otherwise try to unlink the node and try again. if that
         * fails check the full path and try a final time.
         */
        if (res == 0)
            break;

        /*
         * we failed to make the node
         */
        oerrno = errno;
        if ((ign = unlnk_exist(nm, arcn->type)) < 0)
            return(-1);

        if (++pass <= 1)
            continue;

        if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid, NULL) < 0) {
            syswarn(1, oerrno, "Could not create: %s", nm);
            return(-1);
        }
    }

    /*
     * we were able to create the node. set uid/gid, modes and times
     */
    if (pids)
        res = ((arcn->type == PAX_SLK) ?
#if defined(__APPLE__)
               /* Mac OS X doesn't have lchown, so don't bother */
               0 :
#else
               set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) :
#endif
               set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid));
    else