diff -urb cpio-2.6.orig/lib/mkdir.c cpio-2.6/lib/mkdir.c --- cpio-2.6.orig/lib/mkdir.c 2005-04-17 09:36:25.185617560 -0400 +++ cpio-2.6/lib/mkdir.c 2005-04-17 09:36:46.427388320 -0400 @@ -75,15 +75,16 @@ return -1; /* errno is already set. */ case 0: /* Child process. */ + { /* Cheap hack to set mode of new directory. Since this child - process is going away anyway, we zap its umask. - This won't suffice to set SUID, SGID, etc. on this - directory, so the parent process calls chmod afterward. */ + process is going away anyway, we zap its umask. */ + char mode[16]; status = umask (0); /* Get current umask. */ umask (status | (0777 & ~dmode)); /* Set for mkdir. */ - execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); + snprintf(mode, sizeof(mode), "-m=%o", mode); + execl ("/bin/mkdir", "mkdir", dpath, mode, (char *) 0); _exit (1); - + } default: /* Parent process. */ /* Wait for kid to finish. */ while (wait (&status) != cpid) @@ -95,6 +96,6 @@ errno = EIO; return -1; } - return chmod (dpath, dmode); + return 0; } } diff -urb cpio-2.6.orig/src/copyin.c cpio-2.6/src/copyin.c --- cpio-2.6.orig/src/copyin.c 2005-04-17 09:36:25.219612392 -0400 +++ cpio-2.6/src/copyin.c 2005-04-17 09:36:46.430387864 -0400 @@ -389,19 +389,20 @@ continue; } - if (close (out_file_des) < 0) - error (0, errno, "%s", d->header.c_name); - /* File is now copied; set attributes. */ if (!no_chown_flag) - if ((chown (d->header.c_name, + if ((fchown (out_file_des, set_owner_flag ? set_owner : d->header.c_uid, set_group_flag ? set_group : d->header.c_gid) < 0) && errno != EPERM) error (0, errno, "%s", d->header.c_name); - /* chown may have turned off some permissions we wanted. */ - if (chmod (d->header.c_name, (int) d->header.c_mode) < 0) + /* fchown may have turned off some permissions we wanted. */ + if (fchmod (out_file_des, (int) d->header.c_mode) < 0) error (0, errno, "%s", d->header.c_name); + + if (close (out_file_des) < 0) + error (0, errno, "%s", d->header.c_name); + if (retain_time_flag) { times.actime = times.modtime = d->header.c_mtime; @@ -557,9 +558,6 @@ write (out_file_des, "", 1); delayed_seek_count = 0; } - if (close (out_file_des) < 0) - error (0, errno, "%s", file_hdr->c_name); - if (archive_format == arf_crcascii) { if (crc != file_hdr->c_chksum) @@ -569,14 +567,17 @@ /* File is now copied; set attributes. */ if (!no_chown_flag) - if ((chown (file_hdr->c_name, + if ((fchown (out_file_des, set_owner_flag ? set_owner : file_hdr->c_uid, set_group_flag ? set_group : file_hdr->c_gid) < 0) && errno != EPERM) error (0, errno, "%s", file_hdr->c_name); /* chown may have turned off some permissions we wanted. */ - if (chmod (file_hdr->c_name, (int) file_hdr->c_mode) < 0) + if (fchmod (out_file_des, (int) file_hdr->c_mode) < 0) + error (0, errno, "%s", file_hdr->c_name); + + if (close (out_file_des) < 0) error (0, errno, "%s", file_hdr->c_name); if (retain_time_flag) @@ -610,6 +611,8 @@ int cdf_flag; /* True if file is a CDF. */ int cdf_char; /* Index of `+' char indicating a CDF. */ #endif + int fd; /* File descriptor for fchmod */ + struct stat file_stat; if (to_stdout_option) return; @@ -662,7 +665,6 @@ create_all_directories(), so the mkdir will fail because the directory exists. If that's the case, don't complain about it. */ - struct stat file_stat; if ( (errno != EEXIST) || (lstat (file_hdr->c_name, &file_stat) != 0) || !(S_ISDIR (file_stat.st_mode) ) ) @@ -671,18 +673,30 @@ return; } } + fd = open(file_hdr->c_name, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", file_hdr->c_name); + return; + } + if ((fstat(fd, &file_stat) != 0) || !(S_ISDIR(file_stat.st_mode))) { + error (0, errno, "%s", file_hdr->c_name); + close(fd); + return; + } + if (!no_chown_flag) - if ((chown (file_hdr->c_name, + if ((fchown (fd, set_owner_flag ? set_owner : file_hdr->c_uid, set_group_flag ? set_group : file_hdr->c_gid) < 0) && errno != EPERM) error (0, errno, "%s", file_hdr->c_name); /* chown may have turned off some permissions we wanted. */ - if (chmod (file_hdr->c_name, (int) file_hdr->c_mode) < 0) + if (fchmod (fd, (int) file_hdr->c_mode) < 0) error (0, errno, "%s", file_hdr->c_name); + close(fd); #ifdef HPUX_CDF if (cdf_flag) - /* Once we "hide" the directory with the chmod(), + /* Once we "hide" the directory with the fchmod(), we have to refer to it using name+ instead of name. */ file_hdr->c_name [cdf_char] = '+'; #endif @@ -702,6 +716,8 @@ copyin_device(struct new_cpio_header* file_hdr) { int res; /* Result of various function calls. */ + int fd; /* File descriptor for fchmod */ + struct stat file_stat; if (to_stdout_option) return; @@ -755,15 +771,28 @@ error (0, errno, "%s", file_hdr->c_name); return; } + fd = open(file_hdr->c_name, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", file_hdr->c_name); + return; + } + if ((fstat(fd, &file_stat) != 0) || !(S_ISCHR(file_stat.st_mode) || + S_ISBLK(file_stat.st_mode) || S_ISFIFO(file_stat.st_mode) || + S_ISSOCK(file_stat.st_mode)) ) { + error (0, errno, "%s", file_hdr->c_name); + close(fd); + return; + } if (!no_chown_flag) - if ((chown (file_hdr->c_name, + if ((fchown (fd, set_owner_flag ? set_owner : file_hdr->c_uid, set_group_flag ? set_group : file_hdr->c_gid) < 0) && errno != EPERM) error (0, errno, "%s", file_hdr->c_name); /* chown may have turned off some permissions we wanted. */ - if (chmod (file_hdr->c_name, file_hdr->c_mode) < 0) + if (fchmod (fd, file_hdr->c_mode) < 0) error (0, errno, "%s", file_hdr->c_name); + close(fd); if (retain_time_flag) { struct utimbuf times; /* For setting file times. */ diff -urb cpio-2.6.orig/src/copypass.c cpio-2.6/src/copypass.c --- cpio-2.6.orig/src/copypass.c 2005-04-17 09:36:25.219612392 -0400 +++ cpio-2.6/src/copypass.c 2005-04-17 09:36:46.431387712 -0400 @@ -181,18 +181,19 @@ } if (close (in_file_des) < 0) error (0, errno, "%s", input_name.ds_string); - if (close (out_file_des) < 0) - error (0, errno, "%s", output_name.ds_string); /* Set the attributes of the new file. */ if (!no_chown_flag) - if ((chown (output_name.ds_string, + if ((fchown (out_file_des, set_owner_flag ? set_owner : in_file_stat.st_uid, set_group_flag ? set_group : in_file_stat.st_gid) < 0) && errno != EPERM) error (0, errno, "%s", output_name.ds_string); - /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + /* fchown may have turned off some permissions we wanted. */ + if (fchmod (out_file_des, in_file_stat.st_mode) < 0) + error (0, errno, "%s", output_name.ds_string); + /* now that we set permissions, close out file */ + if (close (out_file_des) < 0) error (0, errno, "%s", output_name.ds_string); if (reset_time_flag) { @@ -222,6 +223,7 @@ } else if (S_ISDIR (in_file_stat.st_mode)) { + int fd; /* File descriptor for fchmod */ #ifdef HPUX_CDF cdf_flag = 0; #endif @@ -265,18 +267,31 @@ continue; } } + fd = open(output_name.ds_string, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", output_name.ds_string); + continue; + } + if ((fstat(fd, &out_file_stat) != 0) || + !(S_ISDIR(out_file_stat.st_mode))) { + error (0, errno, "%s", output_name.ds_string); + close(fd); + continue; + } + if (!no_chown_flag) - if ((chown (output_name.ds_string, + if ((fchown (fd, set_owner_flag ? set_owner : in_file_stat.st_uid, set_group_flag ? set_group : in_file_stat.st_gid) < 0) && errno != EPERM) error (0, errno, "%s", output_name.ds_string); /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + if (fchmod (fd, in_file_stat.st_mode) < 0) error (0, errno, "%s", output_name.ds_string); + close(fd); #ifdef HPUX_CDF if (cdf_flag) - /* Once we "hide" the directory with the chmod(), + /* Once we "hide" the directory with the fchmod(), we have to refer to it using name+ isntead of name. */ output_name.ds_string [cdf_char] = '+'; #endif @@ -297,6 +312,7 @@ #endif 0) { + int fd; /* File descriptor for fchmod */ /* Can the current file be linked to a another file? Set link_name to the original file name. */ if (link_flag) @@ -324,15 +340,30 @@ error (0, errno, "%s", output_name.ds_string); continue; } + fd = open(output_name.ds_string, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", output_name.ds_string); + continue; + } + if ((fstat(fd, &out_file_stat) != 0) || + !((S_ISCHR(out_file_stat.st_mode) || + S_ISBLK(out_file_stat.st_mode) || + S_ISFIFO(out_file_stat.st_mode) || + S_ISSOCK(out_file_stat.st_mode)))) { + error (0, errno, "%s", output_name.ds_string); + close(fd); + continue; + } if (!no_chown_flag) - if ((chown (output_name.ds_string, + if ((fchown (fd, set_owner_flag ? set_owner : in_file_stat.st_uid, set_group_flag ? set_group : in_file_stat.st_gid) < 0) && errno != EPERM) error (0, errno, "%s", output_name.ds_string); - /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + /* fchown may have turned off some permissions we wanted. */ + if (fchmod (fd, in_file_stat.st_mode) < 0) error (0, errno, "%s", output_name.ds_string); + close(fd); if (retain_time_flag) { times.actime = times.modtime = in_file_stat.st_mtime; diff -urb cpio-2.6.orig/src/makepath.c cpio-2.6/src/makepath.c --- cpio-2.6.orig/src/makepath.c 2005-04-17 09:36:25.221612088 -0400 +++ cpio-2.6/src/makepath.c 2005-04-17 09:37:45.370427616 -0400 @@ -100,12 +100,14 @@ char *slash; int tmp_mode; /* Initial perms for leading dirs. */ int re_protect; /* Should leading dirs be unwritable? */ + int fd; /* File descriptor for fchmod */ struct ptr_list { char *dirname_end; struct ptr_list *next; }; struct ptr_list *p, *leading_dirs = NULL; + struct stat tstats; /* temporary stats for fchmod */ /* If leading directories shouldn't be writable or executable, or should have set[ug]id or sticky bits set and we are setting @@ -157,8 +159,20 @@ if (verbose_fmt_string != NULL) error (0, 0, verbose_fmt_string, dirpath); + fd = open(dirpath, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", dirpath); + umask (oldmask); + return 1; + } + if ((fstat(fd, &tstats) != 0) || !(S_ISDIR(tstats.st_mode))) { + error (0, errno, "%s", dirpath); + umask (oldmask); + close(fd); + return 1; + } if (owner != (uid_t) -1 && group != (gid_t) -1 - && chown (dirpath, owner, group) + && fchown (fd, owner, group) #ifdef AFS && errno != EPERM #endif @@ -182,10 +196,11 @@ its hidden/setuid bit. Also add the `+' back to its name (since once it's "hidden" we must refer to as `name+' instead of `name'). */ - chmod (dirpath, 04700); + fchmod (fd, 04700); *(slash - 1) = '+'; } #endif + close(fd); } } else if (!S_ISDIR (stats.st_mode)) @@ -222,10 +237,19 @@ } if (verbose_fmt_string != NULL) error (0, 0, verbose_fmt_string, dirpath); - + fd = open(dirpath, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", dirpath); + return 1; + } + if ((fstat(fd, &tstats) != 0) || !(S_ISDIR(tstats.st_mode))) { + error (0, errno, "%s", dirpath); + close(fd); + return 1; + } if (owner != (uid_t) -1 && group != (gid_t) -1) { - if (chown (dirpath, owner, group) + if (fchown (fd, owner, group) #ifdef AFS && errno != EPERM #endif @@ -236,12 +260,12 @@ } } /* chown may have turned off some permission bits we wanted. */ - if ((mode & 07000) != 0 && chmod (dirpath, mode)) + if ((mode & 07000) != 0 && fchmod (fd, mode)) { error (0, errno, "%s", dirpath); retval = 1; } - + close(fd); /* If the mode for leading directories didn't include owner "wx" privileges, we have to reset their protections to the correct value. */ @@ -265,7 +289,7 @@ else { /* We get here if the entire path already exists. */ - + int fd; /* File descriptor for fchmod */ if (!S_ISDIR (stats.st_mode)) { error (0, 0, _("`%s' exists but is not a directory"), dirpath); @@ -273,14 +297,26 @@ return 1; } - /* chown must precede chmod because on some systems, + fd = open(dirpath, O_NOCTTY|O_RDWR); + if (fd < 0) { + error (0, errno, "%s", dirpath); + umask (oldmask); + return 1; + } + if ((fstat(fd, &tstats) != 0) || !(S_ISDIR(tstats.st_mode))) { + error (0, errno, "%s", dirpath); + umask (oldmask); + close(fd); + return 1; + } + /* chown must precede fchmod because on some systems, chown clears the set[ug]id bits for non-superusers, resulting in incorrect permissions. On System V, users can give away files with chown and then not - be able to chmod them. So don't give files away. */ + be able to fchmod them. So don't give files away. */ if (owner != (uid_t) -1 && group != (gid_t) -1 - && chown (dirpath, owner, group) + && fchown (fd, owner, group) #ifdef AFS && errno != EPERM #endif @@ -289,11 +325,12 @@ error (0, errno, "%s", dirpath); retval = 1; } - if (chmod (dirpath, mode)) + if (fchmod (fd, mode)) { error (0, errno, "%s", dirpath); retval = 1; } + close(fd); } umask (oldmask);