Annotation of src/usr.bin/rsync/socket.c, Revision 1.15
1.15 ! deraadt 1: /* $Id: socket.c,v 1.14 2019/02/17 16:34:04 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: #include <sys/socket.h>
19: #include <arpa/inet.h>
20: #include <netinet/in.h>
21:
22: #include <assert.h>
23: #include <ctype.h>
24: #include <errno.h>
25: #include <fcntl.h>
26: #include <inttypes.h>
27: #include <netdb.h>
28: #include <poll.h>
29: #include <resolv.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <unistd.h>
33:
34: #include "extern.h"
35:
36: /*
37: * Defines a resolved IP address for the host
38: * There can be many, IPV4 or IPV6.
39: */
40: struct source {
1.2 benno 41: int family; /* PF_INET or PF_INET6 */
42: char ip[INET6_ADDRSTRLEN]; /* formatted string */
1.1 benno 43: struct sockaddr_storage sa; /* socket */
44: socklen_t salen; /* length of socket buffer */
45: };
46:
47: /*
48: * Connect to an IP address representing a host.
49: * Return <0 on failure, 0 on try another address, >0 on success.
50: */
51: static int
52: inet_connect(struct sess *sess, int *sd,
53: const struct source *src, const char *host)
54: {
55: int c, flags;
56:
1.5 deraadt 57: if (*sd != -1)
1.1 benno 58: close(*sd);
59:
60: LOG2(sess, "trying: %s, %s", src->ip, host);
61:
1.5 deraadt 62: if ((*sd = socket(src->family, SOCK_STREAM, 0)) == -1) {
1.1 benno 63: ERR(sess, "socket");
64: return -1;
65: }
66:
67: /*
68: * Initiate blocking connection.
69: * We use the blocking connect() instead of passing NONBLOCK to
70: * the socket() function because we don't need to do anything
71: * while waiting for this to finish.
72: */
73:
1.7 deraadt 74: c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen);
1.5 deraadt 75: if (c == -1) {
76: if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
1.7 deraadt 77: WARNX(sess, "connect refused: %s, %s",
78: src->ip, host);
1.1 benno 79: return 0;
80: }
81: ERR(sess, "connect");
82: return -1;
83: }
84:
85: /* Set up non-blocking mode. */
86:
1.5 deraadt 87: if ((flags = fcntl(*sd, F_GETFL, 0)) == -1) {
1.1 benno 88: ERR(sess, "fcntl");
89: return -1;
1.5 deraadt 90: } else if (fcntl(*sd, F_SETFL, flags|O_NONBLOCK) == -1) {
1.1 benno 91: ERR(sess, "fcntl");
92: return -1;
93: }
94:
95: return 1;
96: }
97:
98: /*
99: * Resolve the socket addresses for host, both in IPV4 and IPV6.
100: * Once completed, the "dns" pledge may be dropped.
101: * Returns the addresses on success, NULL on failure (sz is always zero,
102: * in this case).
103: */
104: static struct source *
105: inet_resolve(struct sess *sess, const char *host, size_t *sz)
106: {
107: struct addrinfo hints, *res0, *res;
108: struct sockaddr *sa;
109: struct source *src = NULL;
110: size_t i, srcsz = 0;
111: int error;
112:
113: *sz = 0;
114:
115: memset(&hints, 0, sizeof(hints));
116: hints.ai_family = PF_UNSPEC;
1.12 deraadt 117: hints.ai_socktype = SOCK_STREAM;
1.1 benno 118:
1.15 ! deraadt 119: error = getaddrinfo(host, sess->opts->port, &hints, &res0);
1.1 benno 120:
121: LOG2(sess, "resolving: %s", host);
122:
123: if (error == EAI_AGAIN || error == EAI_NONAME) {
1.10 deraadt 124: ERRX(sess, "Could not resolve hostname %s: %s",
1.7 deraadt 125: host, gai_strerror(error));
1.1 benno 126: return NULL;
1.10 deraadt 127: } else if (error == EAI_SERVICE) {
1.15 ! deraadt 128: ERRX(sess, "Could not resolve service '%s': %s",
! 129: sess->opts->port, gai_strerror(error));
1.10 deraadt 130: return NULL;
1.1 benno 131: } else if (error) {
1.10 deraadt 132: ERRX(sess, "getaddrinfo: %s: %s", host, gai_strerror(error));
1.1 benno 133: return NULL;
134: }
135:
136: /* Allocate for all available addresses. */
137:
1.14 deraadt 138: for (res = res0; res != NULL; res = res->ai_next)
1.1 benno 139: if (res->ai_family == AF_INET ||
140: res->ai_family == AF_INET6)
141: srcsz++;
142:
1.5 deraadt 143: if (srcsz == 0) {
1.1 benno 144: ERRX(sess, "no addresses resolved: %s", host);
145: freeaddrinfo(res0);
146: return NULL;
147: }
148:
149: src = calloc(srcsz, sizeof(struct source));
1.5 deraadt 150: if (src == NULL) {
1.1 benno 151: ERRX(sess, "calloc");
152: freeaddrinfo(res0);
153: return NULL;
154: }
155:
1.14 deraadt 156: for (i = 0, res = res0; res != NULL; res = res->ai_next) {
1.1 benno 157: if (res->ai_family != AF_INET &&
158: res->ai_family != AF_INET6)
159: continue;
160:
161: assert(i < srcsz);
162:
163: /* Copy the socket address. */
164:
165: src[i].salen = res->ai_addrlen;
166: memcpy(&src[i].sa, res->ai_addr, src[i].salen);
167:
168: /* Format as a string, too. */
169:
170: sa = res->ai_addr;
1.5 deraadt 171: if (res->ai_family == AF_INET) {
1.1 benno 172: src[i].family = PF_INET;
173: inet_ntop(AF_INET,
1.7 deraadt 174: &(((struct sockaddr_in *)sa)->sin_addr),
175: src[i].ip, INET6_ADDRSTRLEN);
1.1 benno 176: } else {
177: src[i].family = PF_INET6;
178: inet_ntop(AF_INET6,
1.7 deraadt 179: &(((struct sockaddr_in6 *)sa)->sin6_addr),
180: src[i].ip, INET6_ADDRSTRLEN);
1.1 benno 181: }
1.2 benno 182:
1.10 deraadt 183: LOG2(sess, "hostname resolved: %s: %s", host, src[i].ip);
1.1 benno 184: i++;
185: }
186:
187: freeaddrinfo(res0);
188: *sz = srcsz;
189: return src;
190: }
191:
192: /*
193: * Process an rsyncd preamble line.
194: * This is either free-form text or @RSYNCD commands.
195: * Return <0 on failure, 0 on try more lines, >0 on finished.
196: */
197: static int
198: protocol_line(struct sess *sess, const char *host, const char *cp)
199: {
200: int major, minor;
201:
202: if (strncmp(cp, "@RSYNCD: ", 9)) {
203: LOG0(sess, "%s", cp);
204: return 0;
205: }
206:
207: cp += 9;
208: while (isspace((unsigned char)*cp))
209: cp++;
210:
211: /* @RSYNCD: OK indicates that we're finished. */
212:
1.5 deraadt 213: if (strcmp(cp, "OK") == 0)
1.1 benno 214: return 1;
215:
216: /*
217: * Otherwise, all we have left is our version.
218: * There are two formats: x.y (w/submodule) and x.
219: */
220:
1.5 deraadt 221: if (sscanf(cp, "%d.%d", &major, &minor) == 2) {
1.1 benno 222: sess->rver = major;
223: return 0;
1.5 deraadt 224: } else if (sscanf(cp, "%d", &major) == 1) {
1.1 benno 225: sess->rver = major;
226: return 0;
227: }
228:
229: ERRX(sess, "rsyncd protocol error: unknown command");
230: return -1;
231: }
232:
233: /*
1.9 florian 234: * Pledges: dns, inet, unix, unveil, rpath, cpath, wpath, stdio, fattr, chown.
1.1 benno 235: *
1.9 florian 236: * Pledges (dry-run): -unix, -cpath, -wpath, -fattr, -chown.
1.1 benno 237: * Pledges (!preserve_times): -fattr.
238: */
239: int
240: rsync_socket(const struct opts *opts, const struct fargs *f)
241: {
242: struct sess sess;
243: struct source *src = NULL;
244: size_t i, srcsz = 0;
245: int sd = -1, rc = 0, c;
246: char **args, buf[BUFSIZ];
247: uint8_t byte;
248:
249: memset(&sess, 0, sizeof(struct sess));
250: sess.lver = RSYNC_PROTOCOL;
251: sess.opts = opts;
252:
1.5 deraadt 253: assert(f->host != NULL);
254: assert(f->module != NULL);
1.1 benno 255:
1.5 deraadt 256: if ((args = fargs_cmdline(&sess, f)) == NULL) {
1.1 benno 257: ERRX1(&sess, "fargs_cmdline");
258: return 0;
259: }
260:
261: /* Resolve all IP addresses from the host. */
262:
1.5 deraadt 263: if ((src = inet_resolve(&sess, f->host, &srcsz)) == NULL) {
1.1 benno 264: ERRX1(&sess, "inet_resolve");
265: free(args);
266: return 0;
267: }
268:
269: /* Drop the DNS pledge. */
270:
1.9 florian 271: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw inet unveil", NULL) == -1) {
1.1 benno 272: ERR(&sess, "pledge");
273: goto out;
274: }
275:
276: /*
277: * Iterate over all addresses, trying to connect.
278: * When we succeed, then continue using the connected socket.
279: */
280:
281: assert(srcsz);
282: for (i = 0; i < srcsz; i++) {
283: c = inet_connect(&sess, &sd, &src[i], f->host);
284: if (c < 0) {
285: ERRX1(&sess, "inet_connect");
286: goto out;
287: } else if (c > 0)
288: break;
289: }
290:
291: /* Drop the inet pledge. */
1.9 florian 292: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) {
1.1 benno 293: ERR(&sess, "pledge");
294: goto out;
295: }
296:
297: if (i == srcsz) {
298: ERRX(&sess, "cannot connect to host: %s", f->host);
299: goto out;
300: }
301:
302: /* Initiate with the rsyncd version and module request. */
303:
304: LOG2(&sess, "connected: %s, %s", src[i].ip, f->host);
305:
306: (void)snprintf(buf, sizeof(buf), "@RSYNCD: %d", sess.lver);
1.4 deraadt 307: if (!io_write_line(&sess, sd, buf)) {
1.1 benno 308: ERRX1(&sess, "io_write_line");
309: goto out;
310: }
311:
312: LOG2(&sess, "requesting module: %s, %s", f->module, f->host);
313:
1.4 deraadt 314: if (!io_write_line(&sess, sd, f->module)) {
1.1 benno 315: ERRX1(&sess, "io_write_line");
316: goto out;
317: }
318:
319: /*
320: * Now we read the server's response, byte-by-byte, one newline
321: * terminated at a time, limited to BUFSIZ line length.
322: * For this protocol version, this consists of either @RSYNCD
323: * followed by some text (just "ok" and the remote version) or
324: * the message of the day.
325: */
326:
327: for (;;) {
328: for (i = 0; i < sizeof(buf); i++) {
1.4 deraadt 329: if (!io_read_byte(&sess, sd, &byte)) {
1.1 benno 330: ERRX1(&sess, "io_read_byte");
331: goto out;
332: }
1.5 deraadt 333: if ((buf[i] = byte) == '\n')
1.1 benno 334: break;
335: }
336: if (i == sizeof(buf)) {
337: ERRX(&sess, "line buffer overrun");
338: goto out;
1.5 deraadt 339: } else if (i == 0)
1.1 benno 340: continue;
341:
342: /*
343: * The rsyncd protocol isn't very clear as to whether we
344: * get a CRLF or not: I don't actually see this being
345: * transmitted over the wire.
346: */
347:
348: assert(i > 0);
349: buf[i] = '\0';
1.5 deraadt 350: if (buf[i - 1] == '\r')
1.1 benno 351: buf[i - 1] = '\0';
352:
353: if ((c = protocol_line(&sess, f->host, buf)) < 0) {
354: ERRX1(&sess, "protocol_line");
355: goto out;
356: } else if (c > 0)
357: break;
358: }
359:
360: /*
361: * Now we've exchanged all of our protocol information.
362: * We want to send our command-line arguments over the wire,
363: * each with a newline termination.
364: * Use the same arguments when invoking the server, but leave
365: * off the binary name(s).
366: * Emit a standalone newline afterward.
367: */
368:
1.5 deraadt 369: if (f->mode == FARGS_RECEIVER || f->mode == FARGS_SENDER)
1.1 benno 370: i = 3; /* ssh host rsync... */
371: else
372: i = 1; /* rsync... */
373:
1.14 deraadt 374: for ( ; args[i] != NULL; i++)
1.4 deraadt 375: if (!io_write_line(&sess, sd, args[i])) {
1.1 benno 376: ERRX1(&sess, "io_write_line");
377: goto out;
378: }
1.4 deraadt 379: if (!io_write_byte(&sess, sd, '\n')) {
1.1 benno 380: ERRX1(&sess, "io_write_line");
381: goto out;
382: }
383:
384: /*
385: * All data after this point is going to be multiplexed, so turn
386: * on the multiplexer for our reads and writes.
387: */
388:
389: /* Protocol exchange: get the random seed. */
390:
1.4 deraadt 391: if (!io_read_int(&sess, sd, &sess.seed)) {
1.1 benno 392: ERRX1(&sess, "io_read_int");
393: goto out;
394: }
395:
396: /* Now we've completed the handshake. */
397:
398: if (sess.rver < sess.lver) {
1.13 deraadt 399: ERRX(&sess,
400: "remote protocol %d is older than own %d: unsupported\n",
401: sess.rver, sess.lver);
402: rc = 2; /* Protocol incompatibility*/
1.1 benno 403: goto out;
404: }
405:
406: sess.mplex_reads = 1;
407: LOG2(&sess, "read multiplexing enabled");
408:
409: LOG2(&sess, "socket detected client version %" PRId32
410: ", server version %" PRId32 ", seed %" PRId32,
411: sess.lver, sess.rver, sess.seed);
412:
1.5 deraadt 413: assert(f->mode == FARGS_RECEIVER);
1.1 benno 414:
415: LOG2(&sess, "client starting receiver: %s", f->host);
1.4 deraadt 416: if (!rsync_receiver(&sess, sd, sd, f->sink)) {
1.1 benno 417: ERRX1(&sess, "rsync_receiver");
418: goto out;
419: }
420:
421: #if 0
422: /* Probably the EOF. */
423: if (io_read_check(&sess, sd))
424: WARNX(&sess, "data remains in read pipe");
425: #endif
426:
427: rc = 1;
428: out:
429: free(src);
430: free(args);
1.5 deraadt 431: if (sd != -1)
1.1 benno 432: close(sd);
433: return rc;
434: }