Compare commits

..

9 Commits

Author SHA1 Message Date
Martin Pool
9c380e07ef Bump version to 2.3.3pre1. 2002-01-25 07:06:33 +00:00
Martin Pool
61ea0c9d9b Merge signedness security patch from Sebastian Krahmer
<krahmer@suse.de> -- in some cases we were not sufficiently careful
about reading integers from the network.

Possibly some other changes are required.
2002-01-25 03:13:35 +00:00
Martin Pool
2e1d43deb2 Ignore autoconf fluff. 2002-01-25 02:53:48 +00:00
Martin Pool
6780f72000 Add code to compare sin6_addrs. 2002-01-25 02:45:09 +00:00
Martin Pool
39e01d2d4b Back out last change -- to see whether an address is spoofed, we don't
want to look at the whole sockaddr, but rather just at the sin_addr
that it contains.

Also fix silly bug where ai_flags was set incorrectly for getaddrinfo.
2002-01-25 02:43:35 +00:00
Martin Pool
f75502950b compare_addrinfo_sockaddr: Add code to compare AF_INET6 addresses. 2002-01-25 02:37:20 +00:00
Martin Pool
974f27e7e9 Split out code to compare addrinfo and sockaddr into it's own
function.  The comparison cannot be done just byte-by-byte, because
different parts of the sockaddr will be meaningful depending on the
protocol.  It looks like on some systems the library sets the unused
parts to 0, but this is not reliable.  IPv6 not implemented yet.
2002-01-25 02:29:53 +00:00
Martin Pool
af32f69eb0 Doc. 2002-01-25 02:15:58 +00:00
Martin Pool
0cd2f40764 The name resolution stuff is getting complicated -- split it out into
its own file.
2002-01-25 02:13:04 +00:00
13 changed files with 591 additions and 768 deletions

View File

@@ -13,3 +13,6 @@ testtmp
testtmp.*
tls
zlib/dummy
confdefs.h
conftest.c
conftest.log

View File

@@ -29,7 +29,8 @@ ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o backup.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o \
clientname.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o

2
NEWS
View File

@@ -1,4 +1,4 @@
rsync 2.4.8 (26 Jan 2002)
rsync 2.3.3
SECURITY FIXES:

283
clientname.c Normal file
View File

@@ -0,0 +1,283 @@
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file clientname.c
*
* Functions for looking up the remote name or addr of a socket.
*
* This file is now converted to use the new-style getaddrinfo()
* interface, which supports IPv6 but is also supported on recent
* IPv4-only machines. On systems that don't have that interface, we
* emulate it using the KAME implementation.
**/
#include "rsync.h"
static const char default_name[] = "UNKNOWN";
/**
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
/**
* Return the DNS name of the client.
*
* The name is statically cached so that repeated lookups are quick,
* so there is a limit of one lookup per customer.
*
* If anything goes wrong, including the name->addr->name check, then
* we just use "UNKNOWN", so you can use that value in hosts allow
* lines.
**/
char *client_name(int fd)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
static char name_buf[100];
static char port_buf[100];
static int initialised;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
client_sockaddr(fd, &ss, &ss_len);
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
check_name(fd, &ss, ss_len, name_buf, port_buf);
return name_buf;
}
/**
* Get the sockaddr for the client.
*
* If it comes in as an ipv4 address mapped into IPv6 format then we
* convert it back to a regular IPv4.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
* "::ffff:10.130.1.2". If we use it as-is, then the
* reverse lookup might fail or perhaps something else
* bad might happen. So instead we convert it to an
* equivalent address in the IPv4 address family. */
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
/* There is a macro to extract the mapped part
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof(sin->sin_addr));
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf, size_t name_buf_len,
char *port_buf, size_t port_buf_len)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
return 0;
}
/**
* Compare an addrinfo from the resolver to a sockinfo.
*
* Like strcmp, returns 0 for identical.
**/
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
const struct sockaddr_storage *ss)
{
int ss_family = get_sockaddr_family(ss);
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
rprintf(FERROR,
"%s: response family %d != %d\n",
fn, ai->ai_family, ss_family);
return 1;
}
/* The comparison method depends on the particular AF. */
if (ss_family == AF_INET) {
const struct sockaddr_in *sin1, *sin2;
sin1 = (const struct sockaddr_in *) ss;
sin2 = (const struct sockaddr_in *) ai->ai_addr;
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
sizeof sin1->sin_addr);
}
#ifdef INET6
else if (ss_family == AF_INET6) {
const struct sockaddr_in6 *sin1, *sin2;
sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
return memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
sizeof sin1->sin6_addr);
}
#endif /* INET6 */
else {
/* don't know */
return 1;
}
}
/**
* Do a forward lookup on @p name_buf and make sure it corresponds to
* @p ss -- otherwise we may be being spoofed. If we suspect we are,
* then we don't abort the connection but just emit a warning, and
* change @p name_buf to be "UNKNOWN".
**/
int check_name(int fd,
const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf,
const char *port_buf)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof(hints));
hints.ai_family = ss_family;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
name_buf, gai_strerror(error));
strcpy(name_buf, default_name);
return error;
}
/* Given all these results, we expect that one of them will be
* the same as ss. The comparison is a bit complicated. */
for (res = res0; res; res = res->ai_next) {
if (!compare_addrinfo_sockaddr(res, ss))
break; /* OK, identical */
}
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
strcpy(name_buf, default_name);
} else if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}

View File

@@ -27,6 +27,50 @@ extern int delete_mode;
static struct exclude_struct **exclude_list;
/*
* Optimization for special case when all included files are explicitly
* listed without wildcards in the "exclude" list followed by a "- *"
* to exclude the rest.
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
static int only_included_files = 1;
static struct exclude_struct *exclude_the_rest;
int send_included_file_names(int f,struct file_list *flist)
{
struct exclude_struct *ex, **ex_list;
int n;
char *p;
if (!only_included_files || (exclude_the_rest == NULL) || delete_mode)
return 0;
if (verbose > 1) {
rprintf(FINFO,"(using include-only optimization) ");
}
/* set exclude_list to NULL temporarily so check_exclude */
/* will always return true */
ex_list = exclude_list;
exclude_list = NULL;
for (n=0; (ex = ex_list[n]) != NULL; n++) {
if (ex == exclude_the_rest)
break;
p = ex->pattern;
while (*p == '/') {
/* skip the allowed beginning slashes */
p++;
}
/* silently skip files that don't exist to
be more like non-optimized case */
if (access(p,0) == 0)
send_file_name(f,flist,p,0,0);
}
exclude_list = ex_list;
return 1;
}
/* build an exclude structure given a exclude pattern */
static struct exclude_struct *make_exclude(char *pattern, int include)
{
@@ -51,18 +95,15 @@ static struct exclude_struct *make_exclude(char *pattern, int include)
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
ret->regular_exp = 1;
ret->fnmatch_flags = FNM_PATHNAME;
if (strstr(pattern, "**")) {
static int tested;
if (!tested) {
tested = 1;
if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME)==0) {
rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
}
}
ret->fnmatch_flags = 0;
if (!ret->include && (*pattern == '*') && (*(pattern+1) == '\0')) {
exclude_the_rest = ret;
} else {
only_included_files = 0;
}
ret->regular_exp = 1;
ret->fnmatch_flags = strstr(pattern, "**") ? 0 : FNM_PATHNAME;
} else if (!ret->include) {
only_included_files = 0;
}
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
@@ -104,17 +145,15 @@ static int check_one_exclude(char *name,struct exclude_struct *ex,
}
if (ex->regular_exp) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0)
return 1;
}
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/')))
return 1;
}
}
return 0;
@@ -160,6 +199,8 @@ void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
}
free((*list));
*list = NULL;
only_included_files = 1;
exclude_the_rest = NULL;
return;
}
@@ -222,12 +263,6 @@ void send_exclude_list(int f)
{
int i;
extern int remote_version;
extern int list_only, recurse;
/* this is a complete hack - blame Rusty */
if (list_only && !recurse) {
add_exclude("/*/*", 0);
}
if (!exclude_list) {
write_int(f,0);

154
flist.c
View File

@@ -51,60 +51,8 @@ static char topsrcname[MAXPATHLEN];
static struct exclude_struct **local_exclude_list;
static struct file_struct null_file;
static void clean_flist(struct file_list *flist, int strip_root);
static struct string_area *string_area_new(int size)
{
struct string_area *a;
if (size <= 0) size = ARENA_SIZE;
a = malloc(sizeof(*a));
if (!a) out_of_memory("string_area_new");
a->current = a->base = malloc(size);
if (!a->current) out_of_memory("string_area_new buffer");
a->end = a->base + size;
a->next = NULL;
return a;
}
static void string_area_free(struct string_area *a)
{
struct string_area *next;
for ( ; a ; a = next) {
next = a->next;
free(a->base);
}
}
static char *string_area_malloc(struct string_area **ap, int size)
{
char *p;
struct string_area *a;
/* does the request fit into the current space? */
a = *ap;
if (a->current + size >= a->end) {
/* no; get space, move new string_area to front of the list */
a = string_area_new(size > ARENA_SIZE ? size : ARENA_SIZE);
a->next = *ap;
*ap = a;
}
/* have space; do the "allocation." */
p = a->current;
a->current += size;
return p;
}
static char *string_area_strdup(struct string_area **ap, const char *src)
{
char* dest = string_area_malloc(ap, strlen(src) + 1);
return strcpy(dest, src);
}
static void list_file_entry(struct file_struct *f)
{
@@ -351,11 +299,7 @@ static void receive_file_entry(struct file_struct **fptr,
memset((char *)file, 0, sizeof(*file));
(*fptr) = file;
if (l2 >= MAXPATHLEN-l1) {
rprintf(FERROR,"overflow: flags=0x%x l1=%d l2=%d lastname=%s\n",
flags, l1, l2, lastname);
overflow("receive_file_entry");
}
if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry");
strlcpy(thisname,lastname,l1+1);
read_sbuf(f,&thisname[l1],l2);
@@ -469,12 +413,7 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st)
return (st2.st_dev != filesystem_dev);
}
#define STRDUP(ap, p) (ap ? string_area_strdup(ap, p) : strdup(p))
#define MALLOC(ap, i) (ap ? string_area_malloc(ap, i) : malloc(i))
/* create a file_struct for a named file */
struct file_struct *make_file(int f, char *fname, struct string_area **ap,
int noexcludes)
static struct file_struct *make_file(int f, char *fname)
{
struct file_struct *file;
STRUCT_STAT st;
@@ -483,7 +422,6 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
char cleaned_name[MAXPATHLEN];
char linkbuf[MAXPATHLEN];
extern int delete_excluded;
extern int module_id;
strlcpy(cleaned_name, fname, MAXPATHLEN);
cleaned_name[MAXPATHLEN-1] = 0;
@@ -497,14 +435,11 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
if (readlink_stat(fname,&st,linkbuf) != 0) {
io_error = 1;
rprintf(FERROR,"readlink %s: %s\n",
rprintf(FERROR,"%s: %s\n",
fname,strerror(errno));
return NULL;
}
/* we use noexcludes from backup.c */
if (noexcludes) goto skip_excludes;
if (S_ISDIR(st.st_mode) && !recurse) {
rprintf(FINFO,"skipping directory %s\n",fname);
return NULL;
@@ -518,13 +453,7 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
/* f is set to -1 when calculating deletion file list */
if (((f != -1) || !delete_excluded) && !match_file_name(fname,&st))
return NULL;
if (lp_ignore_nonreadable(module_id) && access(fname, R_OK) != 0)
return NULL;
skip_excludes:
if (verbose > 2)
rprintf(FINFO,"make_file(%d,%s)\n",f,fname);
@@ -541,11 +470,11 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
file->dirname = strdup(fname);
lastdir = file->dirname;
}
file->basename = STRDUP(ap, p+1);
file->basename = strdup(p+1);
*p = '/';
} else {
file->dirname = NULL;
file->basename = STRDUP(ap, fname);
file->basename = strdup(fname);
}
file->modtime = st.st_mtime;
@@ -561,12 +490,12 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
#if SUPPORT_LINKS
if (S_ISLNK(st.st_mode)) {
file->link = STRDUP(ap, linkbuf);
file->link = strdup(linkbuf);
}
#endif
if (always_checksum) {
file->sum = (char *)MALLOC(ap, MD4_SUM_LENGTH);
file->sum = (char *)malloc(MD4_SUM_LENGTH);
if (!file->sum) out_of_memory("md4 sum");
/* drat. we have to provide a null checksum for non-regular
files in order to be compatible with earlier versions
@@ -603,7 +532,7 @@ void send_file_name(int f,struct file_list *flist,char *fname,
{
struct file_struct *file;
file = make_file(f,fname, &flist->string_area, 0);
file = make_file(f,fname);
if (!file) return;
@@ -693,6 +622,7 @@ static void send_directory(int f,struct file_list *flist,char *dir)
}
struct file_list *send_file_list(int f,int argc,char *argv[])
{
int i,l;
@@ -709,7 +639,14 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
start_write = stats.total_written;
flist = flist_new();
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
flist->count=0;
flist->malloced = 1000;
flist->files = (struct file_struct **)malloc(sizeof(flist->files[0])*
flist->malloced);
if (!flist->files) out_of_memory("send_file_list");
if (f != -1) {
io_start_buffering(f);
@@ -735,10 +672,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
}
if (link_stat(fname,&st) != 0) {
if (f != -1) {
io_error=1;
rprintf(FERROR,"link_stat %s : %s\n",fname,strerror(errno));
}
io_error=1;
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
continue;
}
@@ -806,7 +741,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (one_file_system)
set_filesystem(fname);
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (!recurse || !send_included_file_names(f,flist))
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (olddir != NULL) {
flist_dir = NULL;
@@ -924,8 +860,7 @@ struct file_list *recv_file_list(int f)
/* if protocol version is >= 17 then recv the io_error flag */
if (f != -1 && remote_version >= 17) {
extern int module_id;
extern int ignore_errors;
if (lp_ignore_errors(module_id) || ignore_errors) {
if (lp_ignore_errors(module_id)) {
read_int(f);
} else {
io_error |= read_int(f);
@@ -991,38 +926,16 @@ int flist_find(struct file_list *flist,struct file_struct *f)
/*
* free up one file
*/
void free_file(struct file_struct *file)
static void free_file(struct file_struct *file)
{
if (!file) return;
if (file->basename) free(file->basename);
if (file->link) free(file->link);
if (file->sum) free(file->sum);
*file = null_file;
memset((char *)file, 0, sizeof(*file));
}
/*
* allocate a new file list
*/
struct file_list *flist_new()
{
struct file_list *flist;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
flist->count=0;
flist->malloced = 1000;
flist->files = (struct file_struct **)malloc(sizeof(flist->files[0])*
flist->malloced);
if (!flist->files) out_of_memory("send_file_list");
#if ARENA_SIZE > 0
flist->string_area = string_area_new(0);
#else
flist->string_area = NULL;
#endif
return flist;
}
/*
* free up all elements in a flist
*/
@@ -1030,14 +943,11 @@ void flist_free(struct file_list *flist)
{
int i;
for (i=1;i<flist->count;i++) {
if (!flist->string_area)
free_file(flist->files[i]);
free_file(flist->files[i]);
free(flist->files[i]);
}
memset((char *)flist->files, 0, sizeof(flist->files[0])*flist->count);
free(flist->files);
if (flist->string_area)
string_area_free(flist->string_area);
memset((char *)flist, 0, sizeof(*flist));
free(flist);
}
@@ -1066,13 +976,7 @@ static void clean_flist(struct file_list *flist, int strip_root)
if (verbose > 1 && !am_server)
rprintf(FINFO,"removing duplicate name %s from file list %d\n",
f_name(flist->files[i-1]),i-1);
/* it's not great that the flist knows the semantics of the
* file memory usage, but i'd rather not add a flag byte
* to that struct. XXX can i use a bit in the flags field? */
if (flist->string_area)
flist->files[i][0] = null_file;
else
free_file(flist->files[i]);
free_file(flist->files[i]);
}
}
@@ -1099,12 +1003,12 @@ static void clean_flist(struct file_list *flist, int strip_root)
if (verbose <= 3) return;
for (i=0;i<flist->count;i++) {
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%.0f\n",
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%d\n",
getpid(), i,
NS(flist->files[i]->dirname),
NS(flist->files[i]->basename),
flist->files[i]->mode,
(double)flist->files[i]->length);
(int)flist->files[i]->length);
}
}

280
io.c
View File

@@ -18,7 +18,7 @@
*/
/*
socket and pipe IO utilities used in rsync
Utilities used in rsync
tridge, June 1996
*/
@@ -27,8 +27,6 @@
/* if no timeout is specified then use a 60 second select timeout */
#define SELECT_TIMEOUT 60
extern int bwlimit;
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd;
@@ -39,13 +37,15 @@ extern int verbose;
extern int io_timeout;
extern struct stats stats;
static int io_error_fd = -1;
static int buffer_f_in = -1;
static void read_loop(int fd, char *buf, size_t len);
void setup_readbuffer(int f_in)
{
buffer_f_in = f_in;
}
static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
if (!io_timeout) return;
@@ -58,50 +58,19 @@ static void check_timeout(void)
t = time(NULL);
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
if (!am_server && !am_daemon) {
rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
}
rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
exit_cleanup(RERR_TIMEOUT);
}
}
/* setup the fd used to propogate errors */
void io_set_error_fd(int fd)
{
io_error_fd = fd;
}
/* read some data from the error fd and write it to the write log code */
static void read_error_fd(void)
{
char buf[200];
int n;
int fd = io_error_fd;
int tag, len;
io_error_fd = -1;
read_loop(fd, buf, 4);
tag = IVAL(buf, 0);
len = tag & 0xFFFFFF;
tag = tag >> 24;
tag -= MPLEX_BASE;
while (len) {
n = len;
if (n > (sizeof(buf)-1)) n = sizeof(buf)-1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
}
io_error_fd = fd;
}
static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
static int no_flush;
static int no_flush_read;
/* read from a socket with IO timeout. return the number of
bytes read. If no bytes can be read then exit, never return
@@ -110,39 +79,24 @@ static int read_timeout(int fd, char *buf, size_t len)
{
int n, ret=0;
no_flush_read++;
io_flush();
no_flush_read--;
while (ret == 0) {
fd_set fds;
struct timeval tv;
int fd_count = fd+1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (io_error_fd != -1) {
FD_SET(io_error_fd, &fds);
if (io_error_fd > fd) fd_count = io_error_fd+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
if (select(fd_count, &fds, NULL, NULL, &tv) < 1) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
check_timeout();
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &fds)) {
read_error_fd();
}
if (!FD_ISSET(fd, &fds)) continue;
n = read(fd, buf, len);
if (n > 0) {
@@ -159,11 +113,14 @@ static int read_timeout(int fd, char *buf, size_t len)
}
if (n == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
(errno == EAGAIN || errno == EWOULDBLOCK)) {
/* this shouldn't happen, if it does then
sleep for a short time to prevent us
chewing too much CPU */
u_sleep(100);
continue;
}
if (n == 0) {
if (eof_error) {
rprintf(FERROR,"unexpected EOF in read_timeout\n");
@@ -171,9 +128,6 @@ static int read_timeout(int fd, char *buf, size_t len)
exit_cleanup(RERR_STREAMIO);
}
/* this prevents us trying to write errors on a dead socket */
io_multiplexing_close();
rprintf(FERROR,"read error: %s\n", strerror(errno));
exit_cleanup(RERR_STREAMIO);
}
@@ -199,6 +153,7 @@ static void read_loop(int fd, char *buf, size_t len)
static int read_unbuffered(int fd, char *buf, size_t len)
{
static int remaining;
char ibuf[4];
int tag, ret=0;
char line[1024];
@@ -214,8 +169,8 @@ static int read_unbuffered(int fd, char *buf, size_t len)
continue;
}
read_loop(fd, line, 4);
tag = IVAL(line, 0);
read_loop(fd, ibuf, 4);
tag = IVAL(ibuf, 0);
remaining = tag & 0xFFFFFF;
tag = tag >> 24;
@@ -238,7 +193,7 @@ static int read_unbuffered(int fd, char *buf, size_t len)
read_loop(fd, line, remaining);
line[remaining] = 0;
rprintf((enum logcode)tag,"%s", line);
rprintf(tag,"%s", line);
remaining = 0;
}
@@ -246,6 +201,40 @@ static int read_unbuffered(int fd, char *buf, size_t len)
}
/* This function was added to overcome a deadlock problem when using
* ssh. It looks like we can't allow our receive queue to get full or
* ssh will clag up. Uggh. */
static void read_check(int f)
{
int n = 8192;
if (f == -1) return;
if (read_buffer_len == 0) {
read_buffer_p = read_buffer;
}
if (n > MAX_READ_BUFFER/4)
n = MAX_READ_BUFFER/4;
if (read_buffer_p != read_buffer) {
memmove(read_buffer,read_buffer_p,read_buffer_len);
read_buffer_p = read_buffer;
}
if (n > (read_buffer_size - read_buffer_len)) {
read_buffer_size += n;
read_buffer = (char *)Realloc(read_buffer,read_buffer_size);
if (!read_buffer) out_of_memory("read check");
read_buffer_p = read_buffer;
}
n = read_unbuffered(f,read_buffer+read_buffer_len,n);
read_buffer_len += n;
}
/* do a buffered read from fd. don't return until all N bytes
have been read. If all N can't be read then exit with an error */
static void readfd(int fd,char *buffer,size_t N)
@@ -253,8 +242,23 @@ static void readfd(int fd,char *buffer,size_t N)
int ret;
int total=0;
if ((read_buffer_len < N) && (N < 1024)) {
read_check(buffer_f_in);
}
while (total < N) {
if (read_buffer_len > 0 && buffer_f_in == fd) {
ret = MIN(read_buffer_len,N-total);
memcpy(buffer+total,read_buffer_p,ret);
read_buffer_p += ret;
read_buffer_len -= ret;
total += ret;
continue;
}
no_flush_read++;
io_flush();
no_flush_read--;
ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
@@ -317,13 +321,19 @@ unsigned char read_byte(int f)
return c;
}
/* write len bytes to fd */
/* write len bytes to fd, possibly reading from buffer_f_in if set
in order to unclog the pipe. don't return until all len
bytes have been written */
static void writefd_unbuffered(int fd,char *buf,size_t len)
{
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count;
struct timeval tv;
int reading=0;
int blocked=0;
no_flush++;
@@ -331,48 +341,46 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
fd_count = fd;
fd_count = fd+1;
if (io_error_fd != -1) {
FD_SET(io_error_fd,&r_fds);
if (io_error_fd > fd_count)
fd_count = io_error_fd;
if (!no_flush_read) {
reading = (buffer_f_in != -1);
}
if (reading) {
FD_SET(buffer_f_in,&r_fds);
if (buffer_f_in > fd)
fd_count = buffer_f_in+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count+1,
io_error_fd != -1?&r_fds:NULL,
count = select(fd_count,
reading?&r_fds:NULL,
&w_fds,NULL,
&tv);
if (count <= 0) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &r_fds)) {
read_error_fd();
if (reading && FD_ISSET(buffer_f_in, &r_fds)) {
read_check(buffer_f_in);
}
if (FD_ISSET(fd, &w_fds)) {
int ret, n = len-total;
ret = write(fd,buf+total,n);
int n = (len-total)>>blocked;
int ret = write(fd,buf+total,n?n:1);
if (ret == -1 && errno == EINTR) {
continue;
}
if (ret == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
msleep(1);
(errno == EAGAIN || errno == EWOULDBLOCK)) {
blocked++;
continue;
}
@@ -381,19 +389,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
exit_cleanup(RERR_STREAMIO);
}
/* Sleep after writing to limit I/O bandwidth */
if (bwlimit)
{
tv.tv_sec = 0;
tv.tv_usec = ret * 1000 / bwlimit;
while (tv.tv_usec > 1000000)
{
tv.tv_sec++;
tv.tv_usec -= 1000000;
}
select(0, NULL, NULL, NULL, &tv);
}
blocked = 0;
total += ret;
if (io_timeout)
@@ -412,43 +408,22 @@ void io_start_buffering(int fd)
{
if (io_buffer) return;
multiplex_out_fd = fd;
io_buffer = (char *)malloc(IO_BUFFER_SIZE);
io_buffer = (char *)malloc(IO_BUFFER_SIZE+4);
if (!io_buffer) out_of_memory("writefd");
io_buffer_count = 0;
/* leave room for the multiplex header in case it's needed */
io_buffer += 4;
}
/* write an message to a multiplexed stream. If this fails then rsync
exits */
static void mplex_write(int fd, enum logcode code, char *buf, size_t len)
{
char buffer[4096];
int n = len;
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
if (n > (sizeof(buffer)-4)) {
n = sizeof(buffer)-4;
}
memcpy(&buffer[4], buf, n);
writefd_unbuffered(fd, buffer, n+4);
len -= n;
buf += n;
if (len) {
writefd_unbuffered(fd, buf, len);
}
}
void io_flush(void)
{
int fd = multiplex_out_fd;
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
mplex_write(fd, FNONE, io_buffer, io_buffer_count);
SIVAL(io_buffer-4, 0, (MPLEX_BASE<<24) + io_buffer_count);
writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4);
} else {
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
@@ -459,27 +434,16 @@ void io_end_buffering(int fd)
{
io_flush();
if (!io_multiplexing_out) {
free(io_buffer);
free(io_buffer-4);
io_buffer = NULL;
}
}
/* some OSes have a bug where an exit causes the pending writes on
a socket to be flushed. Do an explicit shutdown to try to prevent this */
void io_shutdown(void)
{
if (multiplex_out_fd != -1) close(multiplex_out_fd);
if (io_error_fd != -1) close(io_error_fd);
multiplex_out_fd = -1;
io_error_fd = -1;
}
static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
if (!io_buffer || fd != multiplex_out_fd) {
if (!io_buffer) {
writefd_unbuffered(fd, buf, len);
return;
}
@@ -597,31 +561,31 @@ void io_start_multiplex_in(int fd)
{
multiplex_in_fd = fd;
io_flush();
if (read_buffer_len) {
fprintf(stderr,"ERROR: data in read buffer at mplx start\n");
exit_cleanup(RERR_STREAMIO);
}
io_multiplexing_in = 1;
}
/* write an message to the multiplexed error stream */
int io_multiplex_write(enum logcode code, char *buf, size_t len)
/* write an message to the error stream */
int io_multiplex_write(int f, char *buf, size_t len)
{
if (!io_multiplexing_out) return 0;
io_flush();
SIVAL(io_buffer-4, 0, ((MPLEX_BASE + f)<<24) + len);
memcpy(io_buffer, buf, len);
stats.total_written += (len+4);
mplex_write(multiplex_out_fd, code, buf, len);
writefd_unbuffered(multiplex_out_fd, io_buffer-4, len+4);
return 1;
}
/* write a message to the special error fd */
int io_error_write(int f, enum logcode code, char *buf, size_t len)
void io_close_input(int fd)
{
if (f == -1) return 0;
mplex_write(f, code, buf, len);
return 1;
buffer_f_in = -1;
}
/* stop output multiplexing */
void io_multiplexing_close(void)
{
io_multiplexing_out = 0;
}

79
log.c
View File

@@ -24,7 +24,7 @@
#include "rsync.h"
static FILE *logfile;
static int log_error_fd = -1;
static void logit(int priority, char *buf)
{
@@ -77,66 +77,60 @@ void log_open(void)
logit(LOG_INFO,"rsyncd started\n");
#endif
}
/* setup the error file descriptor - used when we are a server
that is receiving files */
void set_error_fd(int fd)
{
log_error_fd = fd;
}
/* this is the underlying (unformatted) rsync debugging function. Call
it with FINFO, FERROR or FLOG */
void rwrite(enum logcode code, char *buf, int len)
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(int fd, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
FILE *f=NULL;
extern int am_daemon;
extern int am_server;
extern int quiet;
/* recursion can happen with certain fatal conditions */
if (quiet && code == FINFO) return;
if (quiet != 0 && fd == FINFO) return;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
buf[len] = 0;
if (code == FLOG) {
if (fd == FLOG) {
if (am_daemon) logit(LOG_INFO, buf);
return;
}
/* first try to pass it off the our sibling */
if (am_server && io_error_write(log_error_fd, code, buf, len)) {
return;
}
/* then try to pass it to the other end */
if (am_server && io_multiplex_write(code, buf, len)) {
return;
}
if (am_daemon) {
static int depth;
int priority = LOG_INFO;
if (code == FERROR) priority = LOG_WARNING;
if (fd == FERROR) priority = LOG_WARNING;
if (depth) return;
depth++;
log_open();
logit(priority, buf);
if (!io_multiplex_write(fd, buf, strlen(buf))) {
logit(priority, buf);
}
depth--;
return;
}
if (code == FERROR) {
if (fd == FERROR) {
f = stderr;
}
if (code == FINFO) {
if (fd == FINFO) {
extern int am_server;
if (am_server)
f = stderr;
else
@@ -149,25 +143,8 @@ void rwrite(enum logcode code, char *buf, int len)
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
}
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(enum logcode code, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
rwrite(code, buf, len);
}
void rflush(enum logcode code)
void rflush(int fd)
{
FILE *f = NULL;
extern int am_daemon;
@@ -176,15 +153,15 @@ void rflush(enum logcode code)
return;
}
if (code == FLOG) {
if (fd == FLOG) {
return;
}
if (code == FERROR) {
if (fd == FERROR) {
f = stderr;
}
if (code == FINFO) {
if (fd == FINFO) {
extern int am_server;
if (am_server)
f = stderr;
@@ -200,7 +177,7 @@ void rflush(enum logcode code)
/* a generic logging routine for send/recv, with parameter
substitiution */
static void log_formatted(enum logcode code,
static void log_formatted(int fd,
char *format, char *op, struct file_struct *file,
struct stats *initial_stats)
{
@@ -292,7 +269,7 @@ static void log_formatted(enum logcode code,
s = p+l;
}
rprintf(code,"%s\n", buf);
rprintf(fd,"%s\n", buf);
}
/* log the outgoing transfer of a file */

View File

@@ -36,12 +36,14 @@ extern char *compare_dest;
extern int make_backups;
extern char *backup_suffix;
static struct delete_list {
dev_t dev;
INO_T inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
/* yuck! This function wouldn't have been necessary if I had the sorting
algorithm right. Unfortunately fixing the sorting algorithm would introduce
a backward incompatibility as file list indexes are sent over the link.
@@ -102,20 +104,17 @@ static void delete_one(struct file_struct *f)
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
void delete_files(struct file_list *flist)
static void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *name;
extern int module_id;
extern int ignore_errors;
extern int max_delete;
static int deletion_count;
if (cvs_exclude)
add_cvs_excludes();
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
if (io_error && !lp_ignore_errors(module_id)) {
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
@@ -138,7 +137,6 @@ void delete_files(struct file_list *flist)
rprintf(FINFO,"deleting in %s\n", name);
for (i=local_file_list->count-1;i>=0;i--) {
if (max_delete && deletion_count > max_delete) break;
if (!local_file_list->files[i]->basename) continue;
if (remote_version < 19 &&
S_ISDIR(local_file_list->files[i]->mode))
@@ -146,12 +144,10 @@ void delete_files(struct file_list *flist)
if (-1 == flist_find(flist,local_file_list->files[i])) {
char *f = f_name(local_file_list->files[i]);
int k = strlen(f) - strlen(backup_suffix);
/* Hi Andrew, do we really need to play with backup_suffix here? */
if (make_backups && ((k <= 0) ||
(strcmp(f+k,backup_suffix) != 0))) {
(void) make_backup(f);
} else {
deletion_count++;
delete_one(local_file_list->files[i]);
}
}
@@ -227,8 +223,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
extern int cleanup_got_literal;
if (verbose > 3) {
rprintf(FINFO,"data recv %d at %.0f\n",
i,(double)offset);
rprintf(FINFO,"data recv %d at %d\n",
i,(int)offset);
}
stats.literal_data += i;
@@ -245,7 +241,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
}
i = -(i+1);
offset2 = i*(OFF_T)n;
offset2 = i*n;
len = n;
if (i == count-1 && remainder != 0)
len = remainder;
@@ -253,15 +249,13 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
i,len,(double)offset2,(double)offset);
rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
if (buf) {
map = map_ptr(buf,offset2,len);
map = map_ptr(buf,offset2,len);
see_token(map, len);
sum_update(map,len);
}
see_token(map, len);
sum_update(map,len);
if (fd != -1 && write_file(fd,map,len) != len) {
rprintf(FERROR,"write failed on %s : %s\n",
@@ -271,7 +265,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
offset += len;
}
end_progress(total_size);
end_progress();
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR,"write failed on %s : %s\n",
@@ -295,8 +289,6 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
}
/* main routine for receiver process. Receiver process runs on the
same host as the generator process. */
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
@@ -320,6 +312,12 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (!delete_after) {
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
}
while (1) {
cleanup_disable();
@@ -400,7 +398,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
rprintf(FINFO,"recv mapped %s of size %d\n",fnamecmp,(int)st.st_size);
} else {
buf = NULL;
}
@@ -471,7 +469,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
finish_transfer(fname, fnametmp, file);
cleanup_disable();
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",

35
rsync.h
View File

@@ -47,8 +47,8 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 24
#define MIN_PROTOCOL_VERSION 15
#define PROTOCOL_VERSION 21
#define MIN_PROTOCOL_VERSION 11
#define MAX_PROTOCOL_VERSION 30
#define RSYNC_PORT 873
@@ -58,12 +58,14 @@
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (256*1024)
#define IO_BUFFER_SIZE (4092)
#define MAX_READ_BUFFER (1024*1024)
#define MAX_ARGS 1000
#define MPLEX_BASE 7
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3};
#define FERROR 1
#define FINFO 2
#define FLOG 3
#include "errcode.h"
@@ -305,20 +307,10 @@ struct file_struct {
};
#define ARENA_SIZE (32 * 1024)
struct string_area {
char *base;
char *end;
char *current;
struct string_area *next;
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
struct string_area *string_area;
};
struct sum_buf {
@@ -467,15 +459,6 @@ extern int errno;
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif
/* work out what fcntl flag to use for non-blocking */
#ifdef O_NONBLOCK
# define NONBLOCK_FLAG O_NONBLOCK
#elif defined(SYSV)
# define NONBLOCK_FLAG O_NDELAY
#else
# define NONBLOCK_FLAG FNDELAY
#endif
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
@@ -491,7 +474,7 @@ extern int errno;
#define NS(s) ((s)?(s):"<NULL>")
/* use magic gcc attributes to catch format errors */
void rprintf(enum logcode , const char *, ...)
void rprintf(int , const char *, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
@@ -510,8 +493,4 @@ size_t strlcpy(char *d, const char *s, size_t bufsize);
size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF))
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)

216
socket.c
View File

@@ -33,8 +33,6 @@
#include "rsync.h"
static const char default_name[] = "UNKNOWN";
/* Establish a proxy connection on an open socket to a web roxy by
* using the CONNECT method. */
@@ -568,220 +566,6 @@ void become_daemon(void)
}
}
/**
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
/**
* Return the DNS name of the client.
*
* The name is statically cached so that repeated lookups are quick,
* so there is a limit of one lookup per customer.
*
* If anything goes wrong, including the name->addr->name check, then
* we just use "UNKNOWN", so you can use that value in hosts allow
* lines.
**/
char *client_name(int fd)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
static char name_buf[100];
static char port_buf[100];
static int initialised;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
client_sockaddr(fd, &ss, &ss_len);
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
check_name(fd, &ss, ss_len, name_buf, port_buf);
return name_buf;
}
/**
* Get the sockaddr for the client.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
* "::ffff:10.130.1.2". If we use it as-is, then the
* reverse lookup might fail or perhaps something else
* bad might happen. So instead we convert it to an
* equivalent address in the IPv4 address family. */
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
/* There is a macro to extract the mapped part
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof(sin->sin_addr));
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf, size_t name_buf_len,
char *port_buf, size_t port_buf_len)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
return 0;
}
/* Do a forward lookup on name_buf and make sure it corresponds to ss
* -- otherwise we may be being spoofed. If we suspect we are, then
* we don't abort the connection but just emit a warning. */
int check_name(int fd,
const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf,
const char *port_buf)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = ss_family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s:%s failed: %s\n",
name_buf, port_buf,
gai_strerror(error));
strcpy(name_buf, default_name);
return error;
}
/* We expect that one of the results will be the same as ss. */
for (res = res0; res; res = res->ai_next) {
if (res->ai_family != ss_family) {
rprintf(FERROR,
"check_name: response family %d != %d\n",
res->ai_family, ss_family);
continue;
}
if (res->ai_addrlen != ss_len) {
rprintf(FERROR,
"check_name: addrlen %d != %d\n",
res->ai_addrlen, ss_len);
continue;
}
if (memcmp(res->ai_addr, ss, res->ai_addrlen) == 0) {
rprintf(FERROR,
"check_name: %d bytes of address identical\n",
res->ai_addrlen);
break;
} else{
rprintf(FERROR,
"check_name: %d bytes of address NOT identical\n",
res->ai_addrlen);
}
}
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
strcpy(name_buf, default_name);
}
if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}
/*******************************************************************
this is like socketpair but uses tcp. It is used by the Samba

181
util.c
View File

@@ -26,81 +26,42 @@
extern int verbose;
/****************************************************************************
Set a fd into nonblocking mode
Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
void set_nonblocking(int fd)
int set_nonblocking(int fd)
{
int val;
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return;
if (!(val & NONBLOCK_FLAG)) {
val |= NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}
/****************************************************************************
Set a fd into blocking mode
****************************************************************************/
void set_blocking(int fd)
{
int val;
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return;
if (val & NONBLOCK_FLAG) {
val &= ~NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}
/* create a file descriptor pair - like pipe() but use socketpair if
possible (because of blocking issues on pipes)
always set non-blocking
*/
int fd_pair(int fd[2])
{
int ret;
#if HAVE_SOCKETPAIR
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
ret = pipe(fd);
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
#endif
if (ret == 0) {
set_nonblocking(fd[0]);
set_nonblocking(fd[1]);
}
return ret;
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
/* this is derived from CVS code
note that in the child STDIN is set to blocking and STDOUT
is set to non-blocking. This is necessary as rsh relies on stdin being blocking
and ssh relies on stdout being non-blocking
if blocking_io is set then use blocking io on both fds. That can be
used to cope with badly broken rsh implementations like the one on
solaris.
*/
/* this is taken from CVS */
int piped_child(char **command,int *f_in,int *f_out)
{
int pid;
int to_child_pipe[2];
int from_child_pipe[2];
extern int blocking_io;
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
@@ -125,10 +86,6 @@ int piped_child(char **command,int *f_in,int *f_out)
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
umask(orig_umask);
set_blocking(STDIN_FILENO);
if (blocking_io) {
set_blocking(STDOUT_FILENO);
}
execvp(command[0], command);
rprintf(FERROR,"Failed to exec %s : %s\n",
command[0],strerror(errno));
@@ -144,6 +101,9 @@ int piped_child(char **command,int *f_in,int *f_out)
*f_in = from_child_pipe[0];
*f_out = to_child_pipe[1];
set_nonblocking(*f_in);
set_nonblocking(*f_out);
return pid;
}
@@ -153,8 +113,8 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
int to_child_pipe[2];
int from_child_pipe[2];
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
@@ -437,6 +397,17 @@ int robust_rename(char *from, char *to)
return -1;
return do_rename(from, to);
#endif
}
/* sleep for a while via select */
void u_sleep(int usec)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = usec;
select(0, NULL, NULL, NULL, &tv);
}
@@ -837,12 +808,12 @@ int u_strcmp(const char *cs1, const char *cs2)
static OFF_T last_ofs;
void end_progress(OFF_T size)
void end_progress(void)
{
extern int do_progress, am_server;
if (do_progress && !am_server) {
rprintf(FINFO,"%.0f (100%%)\n", (double)size);
rprintf(FINFO,"\n");
}
last_ofs = 0;
}
@@ -929,79 +900,3 @@ char *timestring(time_t t)
return(TimeBuf);
}
/*******************************************************************
sleep for a specified number of milliseconds
********************************************************************/
void msleep(int t)
{
int tdiff=0;
struct timeval tval,t1,t2;
gettimeofday(&t1, NULL);
gettimeofday(&t2, NULL);
while (tdiff < t) {
tval.tv_sec = (t-tdiff)/1000;
tval.tv_usec = 1000*((t-tdiff)%1000);
errno = 0;
select(0,NULL,NULL, NULL, &tval);
gettimeofday(&t2, NULL);
tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
(t2.tv_usec - t1.tv_usec)/1000;
}
}
/*******************************************************************
Determine if two file modification times are equivalent (either exact
or in the modification timestamp window established by --modify-window)
Returns 0 if the times should be treated as the same, 1 if the
first is later and -1 if the 2nd is later
*******************************************************************/
int cmp_modtime(time_t file1, time_t file2)
{
time_t diff;
extern int modify_window;
if (file2 > file1) {
if (file2 - file1 <= modify_window) return 0;
return -1;
}
if (file1 - file2 <= modify_window) return 0;
return 1;
}
#ifdef __INSURE__XX
#include <dlfcn.h>
/*******************************************************************
This routine is a trick to immediately catch errors when debugging
with insure. A xterm with a gdb is popped up when insure catches
a error. It is Linux specific.
********************************************************************/
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
{
static int (*fn)();
int ret;
char cmd[1024];
sprintf(cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'",
getpid(), getpid(), getpid());
if (!fn) {
static void *h;
h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
fn = dlsym(h, "_Insure_trap_error");
}
ret = fn(a1, a2, a3, a4, a5, a6);
system(cmd);
return ret;
}
#endif

View File

@@ -1 +1 @@
#define VERSION "2.4.8"
#define VERSION "2.3.3pre1"