Annotation of src/usr.bin/rsync/server.c, Revision 1.4
1.4 ! deraadt 1: /* $Id: server.c,v 1.3 2019/02/11 19:18:36 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>
25:
26: #include "extern.h"
27:
28: static int
29: fcntl_nonblock(struct sess *sess, int fd)
30: {
31: int fl;
32:
1.4 ! deraadt 33: if ((fl = fcntl(fd, F_GETFL, 0)) == -1)
1.1 benno 34: ERR(sess, "fcntl: F_GETFL");
1.4 ! deraadt 35: else if (fcntl(fd, F_SETFL, fl|O_NONBLOCK) == -1)
1.1 benno 36: ERR(sess, "fcntl: F_SETFL");
37: else
38: return 1;
39:
40: return 0;
41: }
42:
43: /*
44: * The server (remote) side of the system.
45: * This parses the arguments given it by the remote shell then moves
46: * into receiver or sender mode depending upon those arguments.
47: *
48: * Pledges: unveil rpath, cpath, wpath, stdio, fattr.
49: *
50: * Pledges (dry-run): -cpath, -wpath, -fattr.
51: * Pledges (!preserve_times): -fattr.
52: */
53: int
54: rsync_server(const struct opts *opts, size_t argc, char *argv[])
55: {
56: struct sess sess;
1.2 benno 57: int fdin = STDIN_FILENO,
1.1 benno 58: fdout = STDOUT_FILENO, c = 0;
59:
60: memset(&sess, 0, sizeof(struct sess));
61: sess.opts = opts;
62:
63: /* Begin by making descriptors non-blocking. */
64:
1.3 deraadt 65: if (!fcntl_nonblock(&sess, fdin) ||
66: !fcntl_nonblock(&sess, fdout)) {
1.1 benno 67: ERRX1(&sess, "fcntl_nonblock");
68: goto out;
69: }
70:
71: /* Standard rsync preamble, server side. */
72:
73: sess.lver = RSYNC_PROTOCOL;
74: sess.seed = arc4random();
75:
1.3 deraadt 76: if (!io_read_int(&sess, fdin, &sess.rver)) {
1.1 benno 77: ERRX1(&sess, "io_read_int");
78: goto out;
1.3 deraadt 79: } else if (!io_write_int(&sess, fdout, sess.lver)) {
1.1 benno 80: ERRX1(&sess, "io_write_int");
81: goto out;
1.3 deraadt 82: } else if (!io_write_int(&sess, fdout, sess.seed)) {
1.1 benno 83: ERRX1(&sess, "io_write_int");
84: goto out;
85: }
86:
87: sess.mplex_writes = 1;
88:
89: if (sess.rver < sess.lver) {
90: ERRX(&sess, "remote protocol is older "
91: "than our own (%" PRId32 " < %" PRId32 "): "
92: "this is not supported",
93: sess.rver, sess.lver);
94: goto out;
95: }
96:
97: LOG2(&sess, "server detected client version %" PRId32
98: ", server version %" PRId32 ", seed %" PRId32,
99: sess.rver, sess.lver, sess.seed);
100:
101: if (sess.opts->sender) {
102: LOG2(&sess, "server starting sender");
103:
104: /*
105: * At this time, I always get a period as the first
106: * argument of the command line.
107: * Let's make it a requirement until I figure out when
108: * that differs.
109: * rsync [flags] "." <source> <...>
110: */
111:
112: if (strcmp(argv[0], ".")) {
113: ERRX(&sess, "first argument must "
114: "be a standalone period");
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.1 benno 138: ERRX(&sess, "server receiver mode "
139: "requires two argument");
140: goto out;
141: } else if (strcmp(argv[0], ".")) {
142: ERRX(&sess, "first argument must "
143: "be a standalone period");
144: goto out;
145: }
146:
1.3 deraadt 147: if (!rsync_receiver(&sess, fdin, fdout, argv[1])) {
1.1 benno 148: ERRX1(&sess, "rsync_receiver");
149: goto out;
150: }
151: }
152:
153: #if 0
154: /* Probably the EOF. */
155: if (io_read_check(&sess, fdin))
156: WARNX(&sess, "data remains in read pipe");
157: #endif
158:
159: c = 1;
160: out:
161: return c;
162: }