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