[BACK]Return to receiver.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Annotation of src/usr.bin/rsync/receiver.c, Revision 1.23

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