Take better care of permissions when copying

This is now better enforced for files, fifos and directories.
This commit is contained in:
Pierre Pronchery 2018-01-28 19:54:38 +01:00
parent 6b018863a3
commit 5da4e529a2

View File

@ -92,10 +92,11 @@ static int _cp_confirm(char const * message)
/* _cp_single
* XXX TOCTOU all over the place (*stat) but seem impossible to avoid */
static int _cp_single_dir(Prefs * prefs, char const * src, char const * dst);
static int _cp_single_fifo(char const * dst);
static int _cp_single_dir(Prefs * prefs, char const * src, char const * dst,
mode_t mode);
static int _cp_single_fifo(char const * dst, mode_t mode);
static int _cp_single_symlink(char const * src, char const * dst);
static int _cp_single_regular(char const * src, char const * dst);
static int _cp_single_regular(char const * src, char const * dst, mode_t mode);
static int _cp_single_p(char const * dst, struct stat * st);
static int _cp_single(Prefs * prefs, char const * src, char const * dst)
@ -125,13 +126,13 @@ static int _cp_single(Prefs * prefs, char const * src, char const * dst)
return _cp_error(dst, 1);
}
if(S_ISDIR(st.st_mode))
ret = _cp_single_dir(prefs, src, dst);
ret = _cp_single_dir(prefs, src, dst, st.st_mode & 0777);
else if(S_ISFIFO(st.st_mode))
ret = _cp_single_fifo(dst);
ret = _cp_single_fifo(dst, st.st_mode & 0666);
else if(S_ISLNK(st.st_mode))
ret = _cp_single_symlink(src, dst);
else
ret = _cp_single_regular(src, dst);
ret = _cp_single_regular(src, dst, st.st_mode & 0777);
if(ret != 0)
return ret;
if(*prefs & CP_PREFS_p) /* XXX TOCTOU */
@ -140,18 +141,20 @@ static int _cp_single(Prefs * prefs, char const * src, char const * dst)
}
/* single_dir */
static int _cp_single_recurse(Prefs * prefs, char const * src,
char const * dst);
static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst,
mode_t mode);
static int _cp_single_dir(Prefs * prefs, char const * src, char const * dst)
static int _cp_single_dir(Prefs * prefs, char const * src, char const * dst,
mode_t mode)
{
if(*prefs & CP_PREFS_R)
return _cp_single_recurse(prefs, src, dst);
return _cp_single_recurse(prefs, src, dst, mode);
fprintf(stderr, "%s%s%s", "cp: ", src, ": Omitting directory\n");
return 0;
}
static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst)
static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst,
mode_t mode)
{
int ret = 0;
Prefs prefs2 = *prefs;
@ -163,7 +166,7 @@ static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst)
char * sdst = NULL;
char * p;
if(mkdir(dst, 0777) != 0 && errno != EEXIST)
if(mkdir(dst, mode) != 0 && errno != EEXIST)
return _cp_error(dst, 1);
srclen = strlen(src);
dstlen = strlen(dst);
@ -198,9 +201,9 @@ static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst)
return ret;
}
static int _cp_single_fifo(char const * dst)
static int _cp_single_fifo(char const * dst, mode_t mode)
{
if(mkfifo(dst, 0666) != 0)
if(mkfifo(dst, mode) != 0)
return _cp_error(dst, 1);
return 0;
}
@ -218,19 +221,23 @@ static int _cp_single_symlink(char const * src, char const * dst)
return 0;
}
static int _cp_single_regular(char const * src, char const * dst)
static int _cp_single_regular(char const * src, char const * dst, mode_t mode)
{
int ret = 0;
FILE * fsrc;
int fd;
FILE * fdst;
char buf[BUFSIZ];
size_t size;
if((fsrc = fopen(src, "r")) == NULL)
return _cp_error(src, 1);
if((fdst = fopen(dst, "w")) == NULL)
if((fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0
|| (fdst = fdopen(fd, "w")) == NULL)
{
ret = _cp_error(dst, 1);
if(fd >= 0)
close(fd);
fclose(fsrc);
return ret;
}