Annotation of src/usr.bin/rsync/receiver.c, Revision 1.7
1.7 ! florian 1: /* $Id: receiver.c,v 1.6 2019/02/12 17:58:35 benno Exp $ */
1.1 benno 2:
3: /*
4: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #include <sys/mman.h>
19: #include <sys/stat.h>
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <inttypes.h>
25: #include <math.h>
26: #include <poll.h>
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <time.h>
31: #include <unistd.h>
32:
33: #include "extern.h"
34:
35: enum pfdt {
36: PFD_SENDER_IN = 0, /* input from the sender */
37: PFD_UPLOADER_IN, /* uploader input from a local file */
38: PFD_DOWNLOADER_IN, /* downloader input from a local file */
39: PFD_SENDER_OUT, /* output to the sender */
40: PFD__MAX
41: };
1.7 ! florian 42:
! 43: int
! 44: rsync_set_metadata(struct sess *sess, int newfile,
! 45: int fd, const struct flist *f, const char *path)
! 46: {
! 47: uid_t uid;
! 48: gid_t gid;
! 49: struct timespec tv[2];
! 50:
! 51: /*
! 52: * Conditionally adjust identifiers.
! 53: * If we have an EPERM, report it but continue on: this just
! 54: * means that we're mapping into an unknown (or disallowed)
! 55: * group identifier.
! 56: */
! 57:
! 58: if (sess->opts->preserve_gids ||
! 59: sess->opts->preserve_uids) {
! 60: uid = sess->opts->preserve_uids ? f->st.uid : -1;
! 61: gid = sess->opts->preserve_gids ? f->st.gid : -1;
! 62: if (fchown(fd, uid, gid) == -1) {
! 63: if (errno != EPERM) {
! 64: ERR(sess, "%s: fchown", path);
! 65: return 0;
! 66: }
! 67: WARNX(sess, "%s: identity unknown or not available "
! 68: "to user.group: %u.%u", f->path, uid, gid);
! 69: } else
! 70: LOG4(sess, "%s: updated uid and/or gid", f->path);
! 71: }
! 72:
! 73: /* Conditionally adjust file modification time. */
! 74:
! 75: if (sess->opts->preserve_times) {
! 76: tv[0].tv_sec = time(NULL);
! 77: tv[0].tv_nsec = 0;
! 78: tv[1].tv_sec = f->st.mtime;
! 79: tv[1].tv_nsec = 0;
! 80: if (futimens(fd, tv) == -1) {
! 81: ERR(sess, "%s: futimens", path);
! 82: return 0;
! 83: }
! 84: LOG4(sess, "%s: updated date", f->path);
! 85: }
! 86:
! 87: return 1;
! 88: }
1.1 benno 89:
1.2 benno 90: /*
1.1 benno 91: * Pledges: unveil, rpath, cpath, wpath, stdio, fattr.
92: * Pledges (dry-run): -cpath, -wpath, -fattr.
93: */
94: int
95: rsync_receiver(struct sess *sess,
96: int fdin, int fdout, const char *root)
97: {
98: struct flist *fl = NULL, *dfl = NULL;
99: size_t i, flsz = 0, dflsz = 0, excl;
100: char *tofree;
101: int rc = 0, dfd = -1, phase = 0, c;
1.2 benno 102: int32_t ioerror;
1.1 benno 103: struct pollfd pfd[PFD__MAX];
104: struct download *dl = NULL;
1.2 benno 105: struct upload *ul = NULL;
1.1 benno 106: mode_t oumask;
107:
1.6 benno 108: if (pledge("stdio rpath wpath cpath fattr getpw unveil", NULL) == -1) {
1.1 benno 109: ERR(sess, "pledge");
110: goto out;
111: }
112:
113: /* Client sends zero-length exclusions. */
114:
1.4 deraadt 115: if (!sess->opts->server &&
116: !io_write_int(sess, fdout, 0)) {
1.1 benno 117: ERRX1(sess, "io_write_int");
118: goto out;
119: }
120:
121: if (sess->opts->server && sess->opts->del) {
1.4 deraadt 122: if (!io_read_size(sess, fdin, &excl)) {
1.1 benno 123: ERRX1(sess, "io_read_size");
124: goto out;
125: } else if (0 != excl) {
126: ERRX(sess, "exclusion list is non-empty");
127: goto out;
128: }
129: }
130:
131: /*
132: * Start by receiving the file list and our mystery number.
133: * These we're going to be touching on our local system.
134: */
135:
1.4 deraadt 136: if (!flist_recv(sess, fdin, &fl, &flsz)) {
1.1 benno 137: ERRX1(sess, "flist_recv");
138: goto out;
1.2 benno 139: }
140:
1.1 benno 141: /* The IO error is sent after the file list. */
142:
1.4 deraadt 143: if (!io_read_int(sess, fdin, &ioerror)) {
1.1 benno 144: ERRX1(sess, "io_read_int");
145: goto out;
146: } else if (0 != ioerror) {
147: ERRX1(sess, "io_error is non-zero");
148: goto out;
149: }
150:
1.5 deraadt 151: if (flsz == 0 && !sess->opts->server) {
1.1 benno 152: WARNX(sess, "receiver has empty file list: exiting");
153: rc = 1;
154: goto out;
1.4 deraadt 155: } else if (!sess->opts->server)
1.1 benno 156: LOG1(sess, "Transfer starting: %zu files", flsz);
157:
158: LOG2(sess, "%s: receiver destination", root);
159:
160: /*
161: * Create the path for our destination directory, if we're not
162: * in dry-run mode (which would otherwise crash w/the pledge).
163: * This uses our current umask: we might set the permissions on
164: * this directory in post_dir().
165: */
166:
1.4 deraadt 167: if (!sess->opts->dry_run) {
1.5 deraadt 168: if ((tofree = strdup(root)) == NULL) {
1.1 benno 169: ERR(sess, "strdup");
170: goto out;
171: } else if (mkpath(sess, tofree) < 0) {
172: ERRX1(sess, "%s: mkpath", root);
173: free(tofree);
174: goto out;
175: }
176: free(tofree);
177: }
178:
179: /*
180: * Disable umask() so we can set permissions fully.
181: * Then open the directory iff we're not in dry_run.
182: */
183:
184: oumask = umask(0);
185:
1.4 deraadt 186: if (!sess->opts->dry_run) {
1.1 benno 187: dfd = open(root, O_RDONLY | O_DIRECTORY, 0);
1.5 deraadt 188: if (dfd == -1) {
1.1 benno 189: ERR(sess, "%s: open", root);
190: goto out;
191: }
192: }
193:
194: /*
195: * Begin by conditionally getting all files we have currently
196: * available in our destination.
197: * XXX: THIS IS A BUG IN OPENBSD 6.4.
198: * For newer version of OpenBSD, this is safe to put after the
199: * unveil.
200: */
201:
1.2 benno 202: if (sess->opts->del &&
1.1 benno 203: sess->opts->recursive &&
1.4 deraadt 204: !flist_gen_dels(sess, root, &dfl, &dflsz, fl, flsz)) {
1.1 benno 205: ERRX1(sess, "flist_gen_local");
206: goto out;
207: }
208:
209: /*
210: * Make our entire view of the file-system be limited to what's
211: * in the root directory.
212: * This prevents us from accidentally (or "under the influence")
213: * writing into other parts of the file-system.
214: */
215:
1.5 deraadt 216: if (unveil(root, "rwc") == -1) {
1.1 benno 217: ERR(sess, "%s: unveil", root);
218: goto out;
1.5 deraadt 219: } else if (unveil(NULL, NULL) == -1) {
1.1 benno 220: ERR(sess, "%s: unveil", root);
221: goto out;
222: }
223:
224: /* If we have a local set, go for the deletion. */
225:
1.4 deraadt 226: if (!flist_del(sess, dfd, dfl, dflsz)) {
1.1 benno 227: ERRX1(sess, "flist_del");
228: goto out;
229: }
230:
231: /* Initialise poll events to listen from the sender. */
232:
233: pfd[PFD_SENDER_IN].fd = fdin;
234: pfd[PFD_UPLOADER_IN].fd = -1;
235: pfd[PFD_DOWNLOADER_IN].fd = -1;
236: pfd[PFD_SENDER_OUT].fd = fdout;
237:
238: pfd[PFD_SENDER_IN].events = POLLIN;
239: pfd[PFD_UPLOADER_IN].events = POLLIN;
240: pfd[PFD_DOWNLOADER_IN].events = POLLIN;
241: pfd[PFD_SENDER_OUT].events = POLLOUT;
242:
1.2 benno 243: ul = upload_alloc(sess, dfd, fdout,
1.1 benno 244: CSUM_LENGTH_PHASE1, fl, flsz, oumask);
1.5 deraadt 245: if (ul == NULL) {
1.1 benno 246: ERRX1(sess, "upload_alloc");
247: goto out;
248: }
249:
250: dl = download_alloc(sess, fdin, fl, flsz, dfd);
1.5 deraadt 251: if (dl == NULL) {
1.1 benno 252: ERRX1(sess, "download_alloc");
253: goto out;
254: }
255:
256: LOG2(sess, "%s: ready for phase 1 data", root);
257:
258: for (;;) {
1.5 deraadt 259: if ((c = poll(pfd, PFD__MAX, INFTIM)) == -1) {
1.1 benno 260: ERR(sess, "poll");
261: goto out;
1.2 benno 262: }
1.1 benno 263:
1.2 benno 264: for (i = 0; i < PFD__MAX; i++)
1.1 benno 265: if (pfd[i].revents & (POLLERR|POLLNVAL)) {
266: ERRX(sess, "poll: bad fd");
267: goto out;
268: } else if (pfd[i].revents & POLLHUP) {
269: ERRX(sess, "poll: hangup");
270: goto out;
271: }
272:
273: /*
274: * If we have a read event and we're multiplexing, we
275: * might just have error messages in the pipe.
276: * It's important to flush these out so that we don't
277: * clog the pipe.
278: * Unset our polling status if there's nothing that
279: * remains in the pipe.
280: */
281:
282: if (sess->mplex_reads &&
283: (POLLIN & pfd[PFD_SENDER_IN].revents)) {
1.4 deraadt 284: if (!io_read_flush(sess, fdin)) {
1.1 benno 285: ERRX1(sess, "io_read_flush");
286: goto out;
1.5 deraadt 287: } else if (sess->mplex_read_remain == 0)
1.1 benno 288: pfd[PFD_SENDER_IN].revents &= ~POLLIN;
289: }
290:
291:
292: /*
293: * We run the uploader if we have files left to examine
294: * (i < flsz) or if we have a file that we've opened and
295: * is read to mmap.
296: */
297:
298: if ((POLLIN & pfd[PFD_UPLOADER_IN].revents) ||
299: (POLLOUT & pfd[PFD_SENDER_OUT].revents)) {
1.2 benno 300: c = rsync_uploader(ul,
301: &pfd[PFD_UPLOADER_IN].fd,
1.1 benno 302: sess, &pfd[PFD_SENDER_OUT].fd);
303: if (c < 0) {
304: ERRX1(sess, "rsync_uploader");
305: goto out;
306: }
307: }
308:
1.2 benno 309: /*
1.1 benno 310: * We need to run the downloader when we either have
311: * read events from the sender or an asynchronous local
312: * open is ready.
313: * XXX: we don't disable PFD_SENDER_IN like with the
314: * uploader because we might stop getting error
315: * messages, which will otherwise clog up the pipes.
316: */
317:
1.2 benno 318: if ((POLLIN & pfd[PFD_SENDER_IN].revents) ||
1.1 benno 319: (POLLIN & pfd[PFD_DOWNLOADER_IN].revents)) {
1.2 benno 320: c = rsync_downloader(dl, sess,
1.1 benno 321: &pfd[PFD_DOWNLOADER_IN].fd);
322: if (c < 0) {
323: ERRX1(sess, "rsync_downloader");
324: goto out;
1.5 deraadt 325: } else if (c == 0) {
326: assert(phase == 0);
1.1 benno 327: phase++;
328: LOG2(sess, "%s: receiver ready "
329: "for phase 2 data", root);
330: break;
331: }
332:
333: /*
334: * FIXME: if we have any errors during the
335: * download, most notably files getting out of
336: * sync between the send and the receiver, then
337: * here we should bump our checksum length and
338: * go into the second phase.
339: */
1.2 benno 340: }
1.1 benno 341: }
342:
343: /* Properly close us out by progressing through the phases. */
344:
1.5 deraadt 345: if (phase == 1) {
1.4 deraadt 346: if (!io_write_int(sess, fdout, -1)) {
1.1 benno 347: ERRX1(sess, "io_write_int");
348: goto out;
1.4 deraadt 349: } else if (!io_read_int(sess, fdin, &ioerror)) {
1.1 benno 350: ERRX1(sess, "io_read_int");
351: goto out;
1.5 deraadt 352: } else if (ioerror != -1) {
1.1 benno 353: ERRX(sess, "expected phase ack");
354: goto out;
355: }
356: }
357:
358: /*
359: * Now all of our transfers are complete, so we can fix up our
360: * directory permissions.
361: */
362:
1.4 deraadt 363: if (!rsync_uploader_tail(ul, sess)) {
1.1 benno 364: ERRX1(sess, "rsync_uploader_tail");
365: goto out;
366: }
367:
368: /* Process server statistics and say good-bye. */
369:
1.4 deraadt 370: if (!sess_stats_recv(sess, fdin)) {
1.1 benno 371: ERRX1(sess, "sess_stats_recv");
372: goto out;
1.4 deraadt 373: } else if (!io_write_int(sess, fdout, -1)) {
1.1 benno 374: ERRX1(sess, "io_write_int");
375: goto out;
376: }
377:
378: LOG2(sess, "receiver finished updating");
379: rc = 1;
380: out:
1.5 deraadt 381: if (dfd != -1)
1.1 benno 382: close(dfd);
383: upload_free(ul);
384: download_free(dl);
385: flist_free(fl, flsz);
386: flist_free(dfl, dflsz);
387: return rc;
388: }