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 /* _cp_single
* XXX TOCTOU all over the place (*stat) but seem impossible to avoid */ * 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_dir(Prefs * prefs, char const * src, char const * dst,
static int _cp_single_fifo(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_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_p(char const * dst, struct stat * st);
static int _cp_single(Prefs * prefs, char const * src, char const * dst) 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); return _cp_error(dst, 1);
} }
if(S_ISDIR(st.st_mode)) 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)) 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)) else if(S_ISLNK(st.st_mode))
ret = _cp_single_symlink(src, dst); ret = _cp_single_symlink(src, dst);
else else
ret = _cp_single_regular(src, dst); ret = _cp_single_regular(src, dst, st.st_mode & 0777);
if(ret != 0) if(ret != 0)
return ret; return ret;
if(*prefs & CP_PREFS_p) /* XXX TOCTOU */ 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 */ /* single_dir */
static int _cp_single_recurse(Prefs * prefs, char const * src, static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst,
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) 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"); fprintf(stderr, "%s%s%s", "cp: ", src, ": Omitting directory\n");
return 0; 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; int ret = 0;
Prefs prefs2 = *prefs; Prefs prefs2 = *prefs;
@ -163,7 +166,7 @@ static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst)
char * sdst = NULL; char * sdst = NULL;
char * p; char * p;
if(mkdir(dst, 0777) != 0 && errno != EEXIST) if(mkdir(dst, mode) != 0 && errno != EEXIST)
return _cp_error(dst, 1); return _cp_error(dst, 1);
srclen = strlen(src); srclen = strlen(src);
dstlen = strlen(dst); dstlen = strlen(dst);
@ -198,9 +201,9 @@ static int _cp_single_recurse(Prefs * prefs, char const * src, char const * dst)
return ret; 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 _cp_error(dst, 1);
return 0; return 0;
} }
@ -218,19 +221,23 @@ static int _cp_single_symlink(char const * src, char const * dst)
return 0; 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; int ret = 0;
FILE * fsrc; FILE * fsrc;
int fd;
FILE * fdst; FILE * fdst;
char buf[BUFSIZ]; char buf[BUFSIZ];
size_t size; size_t size;
if((fsrc = fopen(src, "r")) == NULL) if((fsrc = fopen(src, "r")) == NULL)
return _cp_error(src, 1); 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); ret = _cp_error(dst, 1);
if(fd >= 0)
close(fd);
fclose(fsrc); fclose(fsrc);
return ret; return ret;
} }