コード例 #1
0
/* send a list of available modules to the client. Don't list those
   with "list = False". */
static void send_listing(int fd)
{
	int n = lp_numservices();
	int i;
	
	for (i=0;i<n;i++)
		if (lp_list(i))
		    io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));
}
コード例 #2
0
/* A generic logging routine for send/recv, with parameter substitiution. */
static void log_formatted(enum logcode code, const char *format, const char *op,
			  struct file_struct *file, const char *fname, int iflags,
			  const char *hlink)
{
	char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
	char *p, *s, *c;
	const char *n;
	size_t len, total;
	int64 b;

	*fmt = '%';

	/* We expand % codes one by one in place in buf.  We don't
	 * copy in the terminating null of the inserted strings, but
	 * rather keep going until we reach the null of the format. */
	total = strlcpy(buf, format, sizeof buf);
	if (total > MAXPATHLEN) {
		rprintf(FERROR, "log-format string is WAY too long!\n");
		exit_cleanup(RERR_MESSAGEIO);
	}
	buf[total++] = '\n';
	buf[total] = '\0';

	for (p = buf; (p = strchr(p, '%')) != NULL; ) {
		int humanize = 0;
		s = p++;
		c = fmt + 1;
		while (*p == '\'') {
			humanize++;
			p++;
		}
		if (*p == '-')
			*c++ = *p++;
		while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8)
			*c++ = *p++;
		while (*p == '\'') {
			humanize++;
			p++;
		}
		if (!*p)
			break;
		*c = '\0';
		n = NULL;

		/* Note for %h and %a: it doesn't matter what fd we pass to
		 * client_{name,addr} because rsync_module will already have
		 * forced the answer to be cached (assuming, of course, for %h
		 * that lp_reverse_lookup(module_id) is true). */
		switch (*p) {
		case 'h':
			if (am_daemon) {
				n = lp_reverse_lookup(module_id)
				  ? client_name(0) : undetermined_hostname;
			}
			break;
		case 'a':
			if (am_daemon)
				n = client_addr(0);
			break;
		case 'l':
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 do_big_num(F_LENGTH(file), humanize, NULL));
			n = buf2;
			break;
		case 'U':
			strlcat(fmt, "u", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 uid_ndx ? F_OWNER(file) : 0);
			n = buf2;
			break;
		case 'G':
			if (!gid_ndx || file->flags & FLAG_SKIP_GROUP)
				n = "DEFAULT";
			else {
				strlcat(fmt, "u", sizeof fmt);
				snprintf(buf2, sizeof buf2, fmt,
					 F_GROUP(file));
				n = buf2;
			}
			break;
		case 'p':
			strlcat(fmt, "d", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt, (int)getpid());
			n = buf2;
			break;
		case 'M':
			n = c = timestring(file->modtime);
			while ((c = strchr(c, ' ')) != NULL)
				*c = '-';
			break;
		case 'B':
			c = buf2 + MAXPATHLEN - PERMSTRING_SIZE - 1;
			permstring(c, file->mode);
			n = c + 1; /* skip the type char */
			break;
		case 'o':
			n = op;
			break;
		case 'f':
			if (fname) {
				c = f_name_buf();
				strlcpy(c, fname, MAXPATHLEN);
			} else
				c = f_name(file, NULL);
			if (am_sender && F_PATHNAME(file)) {
				pathjoin(buf2, sizeof buf2,
					 F_PATHNAME(file), c);
				clean_fname(buf2, 0);
				if (fmt[1]) {
					strlcpy(c, buf2, MAXPATHLEN);
					n = c;
				} else
					n = buf2;
			} else if (am_daemon && *c != '/') {
				pathjoin(buf2, sizeof buf2,
					 curr_dir + module_dirlen, c);
				clean_fname(buf2, 0);
				if (fmt[1]) {
					strlcpy(c, buf2, MAXPATHLEN);
					n = c;
				} else
					n = buf2;
			} else {
				clean_fname(c, 0);
				n = c;
			}
			if (*n == '/')
				n++;
			break;
		case 'n':
			if (fname) {
				c = f_name_buf();
				strlcpy(c, fname, MAXPATHLEN);
			} else
				c = f_name(file, NULL);
			if (S_ISDIR(file->mode))
				strlcat(c, "/", MAXPATHLEN);
			n = c;
			break;
		case 'L':
			if (hlink && *hlink) {
				n = hlink;
				strlcpy(buf2, " => ", sizeof buf2);
			} else if (S_ISLNK(file->mode) && !fname) {
				n = F_SYMLINK(file);
				strlcpy(buf2, " -> ", sizeof buf2);
			} else {
				n = "";
				if (!fmt[1])
					break;
				strlcpy(buf2, "    ", sizeof buf2);
			}
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
			n = buf2;
			break;
		case 'm':
			n = lp_name(module_id);
			break;
		case 't':
			n = timestring(time(NULL));
			break;
		case 'P':
			n = full_module_path;
			break;
		case 'u':
			n = auth_user;
			break;
		case 'b':
		case 'c':
			if (!(iflags & ITEM_TRANSFER))
				b = 0;
			else if ((!!am_sender) ^ (*p == 'c'))
				b = total_data_written - initial_data_written;
			else
				b = total_data_read - initial_data_read;
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 do_big_num(b, humanize, NULL));
			n = buf2;
			break;
		case 'C':
			n = NULL;
			if (S_ISREG(file->mode)) {
				if (always_checksum && canonical_checksum(checksum_type))
					n = sum_as_hex(checksum_type, F_SUM(file));
				else if (iflags & ITEM_TRANSFER && canonical_checksum(xfersum_type))
					n = sum_as_hex(xfersum_type, sender_file_sum);
			}
			if (!n) {
				int checksum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type);
				memset(buf2, ' ', checksum_len*2);
				buf2[checksum_len*2] = '\0';
				n = buf2;
			}
			break;
		case 'i':
			if (iflags & ITEM_DELETED) {
				n = "*deleting  ";
				break;
			}
			n  = c = buf2 + MAXPATHLEN - 32;
			c[0] = iflags & ITEM_LOCAL_CHANGE
			      ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
			     : !(iflags & ITEM_TRANSFER) ? '.'
			     : !local_server && *op == 's' ? '<' : '>';
			if (S_ISLNK(file->mode)) {
				c[1] = 'L';
				c[3] = '.';
				c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
				     : !preserve_times || !receiver_symlink_times
				    || (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
			} else {
				c[1] = S_ISDIR(file->mode) ? 'd'
				     : IS_SPECIAL(file->mode) ? 'S'
				     : IS_DEVICE(file->mode) ? 'D' : 'f';
				c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
				c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
				     : !preserve_times ? 'T' : 't';
			}
			c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
			c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
			c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
			c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
			c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
			c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
			c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
			c[11] = '\0';

			if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
				char ch = iflags & ITEM_IS_NEW ? '+' : '?';
				int i;
				for (i = 2; c[i]; i++)
					c[i] = ch;
			} else if (c[0] == '.' || c[0] == 'h' || c[0] == 'c') {
				int i;
				for (i = 2; c[i]; i++) {
					if (c[i] != '.')
						break;
				}
				if (!c[i]) {
					for (i = 2; c[i]; i++)
						c[i] = ' ';
				}
			}
			break;
		}

		/* "n" is the string to be inserted in place of this % code. */
		if (!n)
			continue;
		if (n != buf2 && fmt[1]) {
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt, n);
			n = buf2;
		}
		len = strlen(n);

		/* Subtract the length of the escape from the string's size. */
		total -= p - s + 1;

		if (len + total >= (size_t)sizeof buf) {
			rprintf(FERROR,
				"buffer overflow expanding %%%c -- exiting\n",
				p[0]);
			exit_cleanup(RERR_MESSAGEIO);
		}

		/* Shuffle the rest of the string along to make space for n */
		if (len != (size_t)(p - s + 1))
			memmove(s + len, p + 1, total - (s - buf) + 1);
		total += len;

		/* Insert the contents of string "n", but NOT its null. */
		if (len)
			memcpy(s, n, len);

		/* Skip over inserted string; continue looking */
		p = s + len;
	}

	rwrite(code, buf, total, 0);
}
コード例 #3
0
static int rsync_module(int fd, int i)
{
	int argc=0;
	char *argv[MAX_ARGS];
	char **argp;
	char line[MAXPATHLEN];
	uid_t uid = (uid_t)-2;
	gid_t gid = (gid_t)-2;
	char *p;
	char *addr = client_addr(fd);
	char *host = client_name(fd);
	char *name = lp_name(i);
	int use_chroot = lp_use_chroot(i);
	int start_glob=0;
	int ret;
	char *request=NULL;
	extern int am_sender;
	extern int remote_version;
	extern int am_root;

	if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
		rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n",
			  name, client_name(fd), client_addr(fd));
		return -1;
	}

	if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
		if (errno) {
			rprintf(FERROR,"failed to open lock file %s : %s\n",
				lp_lock_file(i), strerror(errno));
			io_printf(fd,"@ERROR: failed to open lock file %s : %s\n",
				  lp_lock_file(i), strerror(errno));
		} else {
			rprintf(FERROR,"max connections (%d) reached\n",
				lp_max_connections(i));
			io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
		}
		return -1;
	}

	
	auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");

	if (!auth_user) {
		rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: auth failed on module %s\n",name);
		return -1;		
	}

	module_id = i;

	if (lp_read_only(i))
		read_only = 1;

	am_root = (getuid() == 0);

	if (am_root) {
		p = lp_uid(i);
		if (!name_to_uid(p, &uid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid uid %s\n", p);
				io_printf(fd,"@ERROR: invalid uid\n");
				return -1;
			} 
			uid = atoi(p);
		}

		p = lp_gid(i);
		if (!name_to_gid(p, &gid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid gid %s\n", p);
				io_printf(fd,"@ERROR: invalid gid\n");
				return -1;
			} 
			gid = atoi(p);
		}
	}

	p = lp_include_from(i);
	add_exclude_file(p, 1, 1);

	p = lp_include(i);
	add_include_line(p);

	p = lp_exclude_from(i);
	add_exclude_file(p, 1, 0);

	p = lp_exclude(i);
	add_exclude_line(p);

	log_open();

	if (use_chroot) {
		if (chroot(lp_path(i))) {
			rprintf(FERROR,"chroot %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chroot failed\n");
			return -1;
		}

		if (!push_dir("/", 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}

	} else {
		if (!push_dir(lp_path(i), 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}
	}

	if (am_root) {
		if (setgid(gid)) {
			rprintf(FERROR,"setgid %d failed\n", gid);
			io_printf(fd,"@ERROR: setgid failed\n");
			return -1;
		}

		if (setuid(uid)) {
			rprintf(FERROR,"setuid %d failed\n", uid);
			io_printf(fd,"@ERROR: setuid failed\n");
			return -1;
		}

		am_root = (getuid() == 0);
	}

	io_printf(fd,"@RSYNCD: OK\n");

	argv[argc++] = "rsyncd";

	while (1) {
		if (!read_line(fd, line, sizeof(line)-1)) {
			return -1;
		}

		if (!*line) break;

		p = line;

		argv[argc] = strdup(p);
		if (!argv[argc]) {
			return -1;
		}

		if (start_glob) {
			if (start_glob == 1) {
				request = strdup(p);
				start_glob++;
			}
			glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
		} else {
			argc++;
		}

		if (strcmp(line,".") == 0) {
			start_glob = 1;
		}

		if (argc == MAX_ARGS) {
			return -1;
		}
	}

	if (!use_chroot) {
		/*
		 * Note that this is applied to all parameters, whether or not
		 *    they are filenames, but no other legal parameters contain
		 *    the forms that need to be sanitized so it doesn't hurt;
		 *    it is not known at this point which parameters are files
		 *    and which aren't.
		 */
		for (i = 1; i < argc; i++) {
			sanitize_path(argv[i]);
		}
	}

	ret = parse_arguments(argc, argv, 0);

	if (request) {
		if (*auth_user) {
			rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
				am_sender?"on":"to",
				request, auth_user, host, addr);
		} else {
			rprintf(FINFO,"rsync %s %s from %s (%s)\n",
				am_sender?"on":"to",
				request, host, addr);
		}
		free(request);
	}

#if !TRIDGE
	/* don't allow the logs to be flooded too fast */
	if (verbose > 1) verbose = 1;
#endif

	argc -= optind;
	argp = argv + optind;
	optind = 0;

	if (remote_version > 17 && am_sender)
		io_start_multiplex_out(fd);

	if (!ret) {
		option_error();
	}

	if (lp_timeout(i)) {
		extern int io_timeout;
		io_timeout = lp_timeout(i);
	}

	start_server(fd, fd, argc, argp);

	return 0;
}