summaryrefslogtreecommitdiff
path: root/receiver.c
diff options
context:
space:
mode:
authorMartin Pool <mbp@samba.org>2002-01-25 03:13:35 +0000
committerMartin Pool <mbp@samba.org>2002-01-25 03:13:35 +0000
commit61ea0c9d9b9236760e46b76b8b1546fa9f7d0789 (patch)
tree10aa3719e5091c761164909c143e1fe2dc53dd12 /receiver.c
parent2e1d43deb2fe270a97bc0f596d4a0c175fccf2c3 (diff)
downloadrsync-61ea0c9d9b9236760e46b76b8b1546fa9f7d0789.tar.gz
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.
Diffstat (limited to 'receiver.c')
-rw-r--r--receiver.c94
1 files changed, 47 insertions, 47 deletions
diff --git a/receiver.c b/receiver.c
index 5776ff28..bf907029 100644
--- a/receiver.c
+++ b/receiver.c
@@ -1,6 +1,5 @@
-/* -*- c-file-style: "linux" -*-
-
- Copyright (C) 1996-2000 by Andrew Tridgell
+/*
+ Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
@@ -37,12 +36,14 @@ extern char *compare_dest;
extern int make_backups;
extern char *backup_suffix;
+
static struct delete_list {
- DEV64_T dev;
- INO64_T inode;
+ 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.
@@ -83,15 +84,14 @@ static void delete_one(struct file_struct *f)
{
if (!S_ISDIR(f->mode)) {
if (robust_unlink(f_name(f)) != 0) {
- rprintf(FERROR,"delete_one: unlink %s: %s\n",f_name(f),strerror(errno));
+ rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST)
- rprintf(FERROR,"delete_one: rmdir %s: %s\n",
- f_name(f), strerror(errno));
+ rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting directory %s\n",f_name(f));
}
@@ -104,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;
}
@@ -140,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))
@@ -148,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]);
}
}
@@ -179,7 +173,7 @@ static int get_tmpname(char *fnametmp, char *fname)
rprintf(FERROR,"filename too long\n");
return 0;
}
- snprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
+ slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
@@ -192,11 +186,11 @@ static int get_tmpname(char *fnametmp, char *fname)
if (f) {
*f = 0;
- snprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
+ slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
- snprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
+ slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
}
return 1;
@@ -229,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;
@@ -247,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;
@@ -255,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",
@@ -273,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",
@@ -297,15 +289,12 @@ 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)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
- char template[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
@@ -323,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();
@@ -373,7 +368,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
- snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
+ slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
@@ -403,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;
}
@@ -414,7 +409,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
continue;
}
- strlcpy(template, fnametmp, sizeof(template));
+ /* mktemp is deliberately used here instead of mkstemp.
+ because O_EXCL is used on the open, the race condition
+ is not a problem or a security hole, and we want to
+ control the access permissions on the created file. */
+ if (NULL == do_mktemp(fnametmp)) {
+ rprintf(FERROR,"mktemp %s failed\n",fnametmp);
+ receive_data(f_in,buf,-1,NULL,file->length);
+ if (buf) unmap_file(buf);
+ if (fd1 != -1) close(fd1);
+ continue;
+ }
/* we initially set the perms without the
setuid/setgid bits to ensure that there is no race
@@ -422,21 +427,16 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
the lchown. Thanks to snabb@epipe.fi for pointing
this out. We also set it initially without group
access because of a similar race condition. */
- fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
- if (fd2 == -1) {
- rprintf(FERROR,"mkstemp %s failed\n",fnametmp);
- receive_data(f_in,buf,-1,NULL,file->length);
- if (buf) unmap_file(buf);
- continue;
- }
+ fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
because their information should have been previously
transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
- strlcpy(fnametmp, template, sizeof(fnametmp));
- fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
+ fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
@@ -469,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",
@@ -489,7 +489,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
}
if (preserve_hard_links)
- do_hard_links();
+ do_hard_links(flist);
/* now we need to fix any directory permissions that were
modified during the transfer */