Annotation of src/usr.bin/rsync/server.c, Revision 1.10
1.10 ! deraadt 1: /* $Id: server.c,v 1.9 2019/03/23 00:20:55 deraadt Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/stat.h>
18:
19: #include <assert.h>
20: #include <fcntl.h>
21: #include <inttypes.h>
22: #include <stdlib.h>
23: #include <string.h>
24: #include <unistd.h>
1.8 deraadt 25: #include <err.h>
1.1 benno 26:
27: #include "extern.h"
28:
29: static int
30: fcntl_nonblock(struct sess *sess, int fd)
31: {
32: int fl;
33:
1.4 deraadt 34: if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
1.1 benno 35: ERR(sess, "fcntl: F_GETFL");
1.4 deraadt 36: else if (fcntl(fd, F_SETFL, fl|O_NONBLOCK) == -1)
1.1 benno 37: ERR(sess, "fcntl: F_SETFL");
38: else
39: return 1;
40:
41: return 0;
42: }
43:
44: /*
45: * The server (remote) side of the system.
46: * This parses the arguments given it by the remote shell then moves
47: * into receiver or sender mode depending upon those arguments.
1.9 deraadt 48: * Returns exit code 0 on success, 1 on failure, 2 on failure with
49: * incompatible protocols.
1.1 benno 50: */
51: int
52: rsync_server(const struct opts *opts, size_t argc, char *argv[])
53: {
54: struct sess sess;
1.2 benno 55: int fdin = STDIN_FILENO,
1.9 deraadt 56: fdout = STDOUT_FILENO, rc = 1;
1.8 deraadt 57:
58: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
59: NULL) == -1)
60: err(1, "pledge");
1.1 benno 61:
62: memset(&sess, 0, sizeof(struct sess));
63: sess.opts = opts;
64:
65: /* Begin by making descriptors non-blocking. */
66:
1.3 deraadt 67: if (!fcntl_nonblock(&sess, fdin) ||
68: !fcntl_nonblock(&sess, fdout)) {
1.1 benno 69: ERRX1(&sess, "fcntl_nonblock");
70: goto out;
71: }
72:
73: /* Standard rsync preamble, server side. */
74:
75: sess.lver = RSYNC_PROTOCOL;
76: sess.seed = arc4random();
77:
1.3 deraadt 78: if (!io_read_int(&sess, fdin, &sess.rver)) {
1.1 benno 79: ERRX1(&sess, "io_read_int");
80: goto out;
1.3 deraadt 81: } else if (!io_write_int(&sess, fdout, sess.lver)) {
1.1 benno 82: ERRX1(&sess, "io_write_int");
83: goto out;
1.3 deraadt 84: } else if (!io_write_int(&sess, fdout, sess.seed)) {
1.1 benno 85: ERRX1(&sess, "io_write_int");
86: goto out;
87: }
88:
89: sess.mplex_writes = 1;
90:
91: if (sess.rver < sess.lver) {
1.7 benno 92: ERRX(&sess,
93: "remote protocol %d is older than our own %d: unsupported",
94: sess.rver, sess.lver);
95: rc = 2;
1.1 benno 96: goto out;
97: }
98:
1.10 ! deraadt 99: LOG2(&sess, "server detected client version %d, server version %d, seed %d",
! 100: sess.rver, sess.lver, sess.seed);
1.1 benno 101:
102: if (sess.opts->sender) {
103: LOG2(&sess, "server starting sender");
104:
105: /*
106: * At this time, I always get a period as the first
107: * argument of the command line.
108: * Let's make it a requirement until I figure out when
109: * that differs.
110: * rsync [flags] "." <source> <...>
111: */
112:
113: if (strcmp(argv[0], ".")) {
1.10 ! deraadt 114: ERRX(&sess, "first argument must be a standalone period");
1.1 benno 115: goto out;
116: }
117: argv++;
118: argc--;
1.4 deraadt 119: if (argc == 0) {
1.1 benno 120: ERRX(&sess, "must have arguments");
121: goto out;
122: }
123:
1.3 deraadt 124: if (!rsync_sender(&sess, fdin, fdout, argc, argv)) {
1.1 benno 125: ERRX1(&sess, "rsync_sender");
126: goto out;
127: }
128: } else {
129: LOG2(&sess, "server starting receiver");
130:
131: /*
132: * I don't understand why this calling convention
133: * exists, but we must adhere to it.
134: * rsync [flags] "." <destination>
135: */
136:
1.4 deraadt 137: if (argc != 2) {
1.10 ! deraadt 138: ERRX(&sess, "server receiver mode requires two argument");
1.1 benno 139: goto out;
140: } else if (strcmp(argv[0], ".")) {
1.10 ! deraadt 141: ERRX(&sess, "first argument must be a standalone period");
1.1 benno 142: goto out;
143: }
144:
1.3 deraadt 145: if (!rsync_receiver(&sess, fdin, fdout, argv[1])) {
1.1 benno 146: ERRX1(&sess, "rsync_receiver");
147: goto out;
148: }
149: }
150:
151: #if 0
152: /* Probably the EOF. */
153: if (io_read_check(&sess, fdin))
154: WARNX(&sess, "data remains in read pipe");
155: #endif
156:
1.9 deraadt 157: rc = 0;
1.1 benno 158: out:
1.7 benno 159: return rc;
1.1 benno 160: }