diff options
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r-- | src/firejail/util.c | 91 |
1 files changed, 66 insertions, 25 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c index 10000e912..44891ce2d 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -169,6 +169,25 @@ void logerr(const char *msg) { | |||
169 | closelog(); | 169 | closelog(); |
170 | } | 170 | } |
171 | 171 | ||
172 | static int copy_file_by_fd(int src, int dst) { | ||
173 | assert(src >= 0); | ||
174 | assert(dst >= 0); | ||
175 | |||
176 | ssize_t len; | ||
177 | static const int BUFLEN = 1024; | ||
178 | unsigned char buf[BUFLEN]; | ||
179 | while ((len = read(src, buf, BUFLEN)) > 0) { | ||
180 | int done = 0; | ||
181 | while (done != len) { | ||
182 | int rv = write(dst, buf + done, len - done); | ||
183 | if (rv == -1) | ||
184 | return -1; | ||
185 | done += rv; | ||
186 | } | ||
187 | } | ||
188 | fflush(0); | ||
189 | return 0; | ||
190 | } | ||
172 | 191 | ||
173 | // return -1 if error, 0 if no error; if destname already exists, return error | 192 | // return -1 if error, 0 if no error; if destname already exists, return error |
174 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | 193 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { |
@@ -190,33 +209,16 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
190 | return -1; | 209 | return -1; |
191 | } | 210 | } |
192 | 211 | ||
193 | // copy | 212 | int errors = copy_file_by_fd(src, dst); |
194 | ssize_t len; | 213 | if (!errors) { |
195 | static const int BUFLEN = 1024; | 214 | if (fchown(dst, uid, gid) == -1) |
196 | unsigned char buf[BUFLEN]; | 215 | errExit("fchown"); |
197 | while ((len = read(src, buf, BUFLEN)) > 0) { | 216 | if (fchmod(dst, mode) == -1) |
198 | int done = 0; | 217 | errExit("fchmod"); |
199 | while (done != len) { | ||
200 | int rv = write(dst, buf + done, len - done); | ||
201 | if (rv == -1) { | ||
202 | close(src); | ||
203 | close(dst); | ||
204 | return -1; | ||
205 | } | ||
206 | |||
207 | done += rv; | ||
208 | } | ||
209 | } | 218 | } |
210 | fflush(0); | ||
211 | |||
212 | if (fchown(dst, uid, gid) == -1) | ||
213 | errExit("fchown"); | ||
214 | if (fchmod(dst, mode) == -1) | ||
215 | errExit("fchmod"); | ||
216 | |||
217 | close(src); | 219 | close(src); |
218 | close(dst); | 220 | close(dst); |
219 | return 0; | 221 | return errors; |
220 | } | 222 | } |
221 | 223 | ||
222 | // return -1 if error, 0 if no error | 224 | // return -1 if error, 0 if no error |
@@ -241,6 +243,45 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid | |||
241 | waitpid(child, NULL, 0); | 243 | waitpid(child, NULL, 0); |
242 | } | 244 | } |
243 | 245 | ||
246 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | ||
247 | // open destination | ||
248 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
249 | if (dst < 0) { | ||
250 | fprintf(stderr, "Warning: cannot open destination file %s, file not copied\n", destname); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | pid_t child = fork(); | ||
255 | if (child < 0) | ||
256 | errExit("fork"); | ||
257 | if (child == 0) { | ||
258 | // drop privileges | ||
259 | drop_privs(0); | ||
260 | |||
261 | int src = open(srcname, O_RDONLY); | ||
262 | if (src < 0) { | ||
263 | fprintf(stderr, "Warning: cannot open source file %s, file not copied\n", srcname); | ||
264 | } else { | ||
265 | if (copy_file_by_fd(src, dst)) { | ||
266 | fprintf(stderr, "Warning: cannot copy %s\n", srcname); | ||
267 | } | ||
268 | close(src); | ||
269 | } | ||
270 | close(dst); | ||
271 | #ifdef HAVE_GCOV | ||
272 | __gcov_flush(); | ||
273 | #endif | ||
274 | _exit(0); | ||
275 | } | ||
276 | // wait for the child to finish | ||
277 | waitpid(child, NULL, 0); | ||
278 | if (fchown(dst, uid, gid) == -1) | ||
279 | errExit("fchown"); | ||
280 | if (fchmod(dst, mode) == -1) | ||
281 | errExit("fchmod"); | ||
282 | close(dst); | ||
283 | } | ||
284 | |||
244 | // return -1 if error, 0 if no error | 285 | // return -1 if error, 0 if no error |
245 | void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode) { | 286 | void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode) { |
246 | pid_t child = fork(); | 287 | pid_t child = fork(); |
@@ -864,4 +905,4 @@ errexit: | |||
864 | close(fd); | 905 | close(fd); |
865 | fprintf(stderr, "Error: cannot read %s\n", fname); | 906 | fprintf(stderr, "Error: cannot read %s\n", fname); |
866 | exit(1); | 907 | exit(1); |
867 | } \ No newline at end of file | 908 | } |