Ejemplo n.º 1
0
void
proc_dir(void)
{
	DIRDATA *dblk;
	long cnt;

	if (dirp == NULL)
		return;
	/*
	 * read backwards through the file and process each directory
	 */
	cnt = dircnt;
	while (--cnt >= 0) {
		/*
		 * frc_mode set, make sure we set the file modes even if
		 * the user didn't ask for it (see file_subs.c for more info)
		 */
		dblk = &dirp[cnt];
		if (pmode || dblk->frc_mode)
			set_pmode(dblk->name, dblk->mode);
		if (patime || pmtime)
			set_ftime(dblk->name, dblk->mtime, dblk->atime, 0);
		free(dblk->name);
	}

	free(dirp);
	dirp = NULL;
	dircnt = 0;
}
Ejemplo n.º 2
0
void
file_close(ARCHD *arcn, int fd)
{
    int res = 0;

    if (fd < 0)
        return;
    if (close(fd) < 0)
        syswarn(0, errno, "Unable to close file descriptor on %s",
                arcn->name);

    /*
     * set owner/groups first as this may strip off mode bits we want
     * then set file permission modes. Then set file access and
     * modification times.
     */
    if (pids)
        res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid);

    /*
     * IMPORTANT SECURITY NOTE:
     * if not preserving mode or we cannot set uid/gid, then PROHIBIT
     * set uid/gid bits
     */
    if (!pmode || res)
        arcn->sb.st_mode &= ~(SETBITS);
    if (pmode)
        set_pmode(arcn->name, arcn->sb.st_mode);
    if (patime || pmtime)
        set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
}
Ejemplo n.º 3
0
void
proc_dir(void)
{
	char name[PAXPATHLEN+1];
	DIRDATA dblk;
	u_long cnt;

	if (dirfd < 0)
		return;
	/*
	 * read backwards through the file and process each directory
	 */
	for (cnt = 0; cnt < dircnt; ++cnt) {
		/*
		 * read the trailer, then the file name, if this fails
		 * just give up.
		 */
		if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0)
			break;
		if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk))
			break;
		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
			break;
		if (read(dirfd, name, dblk.nlen) != dblk.nlen)
			break;
		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
			break;

		/*
		 * frc_mode set, make sure we set the file modes even if
		 * the user didn't ask for it (see file_subs.c for more info)
		 */
		if (pmode || dblk.frc_mode)
			set_pmode(name, dblk.mode);
		if (patime || pmtime)
			set_ftime(name, dblk.mtime, dblk.atime, 0);
	}

	close(dirfd);
	dirfd = -1;
	if (cnt != dircnt)
		paxwarn(1,"Unable to set mode and times for created directories");
	return;
}
Ejemplo n.º 4
0
void
proc_dir(void)
{
#ifdef DIRS_USE_FILE
	char name[PAXPATHLEN+1];
	DIRDATA dblk;
	u_long cnt;

	if (dirfd < 0)
		return;
	/*
	 * read backwards through the file and process each directory
	 */
	for (cnt = 0; cnt < dircnt; ++cnt) {
		/*
		 * read the trailer, then the file name, if this fails
		 * just give up.
		 */
		if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0)
			break;
		if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk))
			break;
		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
			break;
		if (xread(dirfd, name, dblk.nlen) != dblk.nlen)
			break;
		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
			break;

		/*
		 * frc_mode set, make sure we set the file modes even if
		 * the user didn't ask for it (see file_subs.c for more info)
		 */
		if (pmode || dblk.frc_mode)
			set_pmode(name, dblk.mode);
		if (patime || pmtime)
			set_ftime(name, dblk.mtime, dblk.atime, 0, 0);
		if (pfflags)
			set_chflags(name, dblk.fflags);
	}

	(void)close(dirfd);
	dirfd = -1;
	if (cnt != dircnt)
		tty_warn(1,
		    "Unable to set mode and times for created directories");
	return;
#else
	DIRDATA *dblk;

	for (dblk = dirdata_head; dblk != NULL; dblk = dirdata_head) {
		dirdata_head = dblk->next;

		/*
		 * frc_mode set, make sure we set the file modes even if
		 * the user didn't ask for it (see file_subs.c for more info)
		 */
		if (pmode || dblk->frc_mode)
			set_pmode(dblk->name, dblk->mode);
		if (patime || pmtime)
			set_ftime(dblk->name, dblk->mtime, dblk->atime, 0, 0);
		if (pfflags)
			set_chflags(dblk->name, dblk->fflags);

		free(dblk->name);
		free(dblk);
	}
#endif /* DIRS_USE_FILE */
}
Ejemplo n.º 5
0
int
chk_path( char *name, uid_t st_uid, gid_t st_gid)
{
    char *spt = name;
    struct stat sb;
    int retval = -1;

    /*
     * watch out for paths with nodes stored directly in / (e.g. /bozo)
     */
    if (*spt == '/')
        ++spt;

    for(;;) {
        /*
         * work foward from the first / and check each part of the path
         */
        spt = strchr(spt, '/');
        if (spt == NULL)
            break;
        *spt = '\0';

        /*
         * if it exists we assume it is a directory, it is not within
         * the spec (at least it seems to read that way) to alter the
         * file system for nodes NOT EXPLICITLY stored on the archive.
         * If that assumption is changed, you would test the node here
         * and figure out how to get rid of it (probably like some
         * recursive unlink()) or fix up the directory permissions if
         * required (do an access()).
         */
        if (lstat(name, &sb) == 0) {
            *(spt++) = '/';
            continue;
        }

        /*
         * the path fails at this point, see if we can create the
         * needed directory and continue on
         */
        if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
            *spt = '/';
            retval = -1;
            break;
        }

        /*
         * we were able to create the directory. We will tell the
         * caller that we found something to fix, and it is ok to try
         * and create the node again.
         */
        retval = 0;
        if (pids)
            (void)set_ids(name, st_uid, st_gid);

        /*
         * make sure the user doen't have some strange umask that
         * causes this newly created directory to be unusable. We fix
         * the modes and restore them back to the creation default at
         * the end of pax
         */
        if ((access(name, R_OK | W_OK | X_OK) < 0) &&
                (lstat(name, &sb) == 0)) {
            set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
            add_dir(name, spt - name, &sb, 1);
        }
        *(spt++) = '/';
        continue;
    }
    return(retval);
}
Ejemplo n.º 6
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);
}
Ejemplo 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 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;
}
Ejemplo n.º 8
0
void
file_close(ARCHD *arcn, int fd)
{
	char *tmp_name;
	int res;

	if (fd < 0)
		return;

	tmp_name = (arcn->tmp_name != NULL) ? arcn->tmp_name : arcn->name;

	if (close(fd) < 0)
		syswarn(0, errno, "Cannot close file descriptor on %s",
		    tmp_name);

	/*
	 * set owner/groups first as this may strip off mode bits we want
	 * then set file permission modes. Then set file access and
	 * modification times.
	 */
	if (pids)
		res = set_ids(tmp_name, 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
	 * set uid/gid bits but restore the file modes (since mkstemp doesn't).
	 */
	if (!pmode || res)
		arcn->sb.st_mode &= ~SETBITS(0);
	if (pmode)
		set_pmode(tmp_name, arcn->sb.st_mode);
	else
		set_pmode(tmp_name,
		    apply_umask((arcn->sb.st_mode & FILEBITS(0))));
	if (patime || pmtime)
		set_ftime(tmp_name, arcn->sb.st_mtime,
		    arcn->sb.st_atime, 0, 0);

	/* Did we write directly to the target file? */
	if (arcn->tmp_name == NULL)
		return;

	/*
	 * Finally, now the temp file is fully instantiated rename it to
	 * the desired file name.
	 */
	if (rename(tmp_name, arcn->name) < 0) {
		syswarn(0, errno, "Cannot rename %s to %s",
		    tmp_name, arcn->name);
		(void)unlink(tmp_name);
	}

#if HAVE_STRUCT_STAT_ST_FLAGS
	if (pfflags && arcn->type != PAX_SLK)
		set_chflags(arcn->name, arcn->sb.st_flags);
#endif

	free(arcn->tmp_name);
	arcn->tmp_name = NULL;
	xtmp_name = NULL;
}