From 5da4e529a22ad8e3b1148fa35325d7e5e9f5fcff Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 28 Jan 2018 19:54:38 +0100 Subject: [PATCH] Take better care of permissions when copying This is now better enforced for files, fifos and directories. --- src/cp.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/cp.c b/src/cp.c index f056e52..d93fc26 100644 --- a/src/cp.c +++ b/src/cp.c @@ -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; }