diff options
author | Martin Pool <mbp@samba.org> | 2002-01-25 03:13:35 +0000 |
---|---|---|
committer | Martin Pool <mbp@samba.org> | 2002-01-25 03:13:35 +0000 |
commit | 61ea0c9d9b9236760e46b76b8b1546fa9f7d0789 (patch) | |
tree | 10aa3719e5091c761164909c143e1fe2dc53dd12 /receiver.c | |
parent | 2e1d43deb2fe270a97bc0f596d4a0c175fccf2c3 (diff) | |
download | rsync-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.c | 94 |
1 files changed, 47 insertions, 47 deletions
@@ -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 */ |