Annotation of src/usr.bin/rsync/server.c, Revision 1.9
1.9 ! deraadt 1: /* $Id: server.c,v 1.8 2019/03/06 18:37:22 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:
99: LOG2(&sess, "server detected client version %" PRId32
100: ", server version %" PRId32 ", seed %" PRId32,
101: sess.rver, sess.lver, sess.seed);
102:
103: if (sess.opts->sender) {
104: LOG2(&sess, "server starting sender");
105:
106: /*
107: * At this time, I always get a period as the first
108: * argument of the command line.
109: * Let's make it a requirement until I figure out when
110: * that differs.
111: * rsync [flags] "." <source> <...>
112: */
113:
114: if (strcmp(argv[0], ".")) {
115: ERRX(&sess, "first argument must "
116: "be a standalone period");
117: goto out;
118: }
119: argv++;
120: argc--;
1.4 deraadt 121: if (argc == 0) {
1.1 benno 122: ERRX(&sess, "must have arguments");
123: goto out;
124: }
125:
1.3 deraadt 126: if (!rsync_sender(&sess, fdin, fdout, argc, argv)) {
1.1 benno 127: ERRX1(&sess, "rsync_sender");
128: goto out;
129: }
130: } else {
131: LOG2(&sess, "server starting receiver");
132:
133: /*
134: * I don't understand why this calling convention
135: * exists, but we must adhere to it.
136: * rsync [flags] "." <destination>
137: */
138:
1.4 deraadt 139: if (argc != 2) {
1.1 benno 140: ERRX(&sess, "server receiver mode "
141: "requires two argument");
142: goto out;
143: } else if (strcmp(argv[0], ".")) {
144: ERRX(&sess, "first argument must "
145: "be a standalone period");
146: goto out;
147: }
148:
1.3 deraadt 149: if (!rsync_receiver(&sess, fdin, fdout, argv[1])) {
1.1 benno 150: ERRX1(&sess, "rsync_receiver");
151: goto out;
152: }
153: }
154:
155: #if 0
156: /* Probably the EOF. */
157: if (io_read_check(&sess, fdin))
158: WARNX(&sess, "data remains in read pipe");
159: #endif
160:
1.9 ! deraadt 161: rc = 0;
1.1 benno 162: out:
1.7 benno 163: return rc;
1.1 benno 164: }