use mkstemp on systems where it is secure
authorAndrew Tridgell <tridge@samba.org>
Wed, 2 May 2001 08:33:18 +0000 (08:33 +0000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 2 May 2001 08:33:18 +0000 (08:33 +0000)
Makefile.in
acconfig.h
configure.in
lib/compat.c
receiver.c
syscall.c

index 53a91ba..3bf7d49 100644 (file)
@@ -54,17 +54,14 @@ install-strip:
        $(MAKE) INSTALLCMD='$(INSTALLCMD) -s' install
 
 rsync: $(OBJS)
-       @-echo "    Note: The link command may give a warning about use of mktemp."
-       @-echo "    The warning may be ignored because rsync uses this function in a safe way."
        $(CC) $(CFLAGS) $(LDFLAGS) -o rsync $(OBJS) $(LIBS)
 
 Makefile: Makefile.in configure config.status
        echo "WARNING: You need to run ./config.status --recheck"
 
-# It's OK if this fails, because we don't require people to have
-# autoconf installed.
+# don't actually run autoconf, just issue a warning
 configure: configure.in
-       -cd $(srcdir) && autoconf
+       echo "WARNING: you need to rerun autoconf"
 
 rsync.1: rsync.yo
        yodl2man -o rsync.1 rsync.yo
index 7028d74..4033a94 100644 (file)
@@ -13,3 +13,4 @@
 #undef REPLACE_INET_ATON
 #undef HAVE_GETTIMEOFDAY_TZ
 #undef HAVE_SOCKETPAIR
+#undef HAVE_SECURE_MKSTEMP
index cbd1f24..d8dd6c0 100644 (file)
@@ -231,6 +231,28 @@ if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
     AC_DEFINE(HAVE_GETTIMEOFDAY_TZ)
 fi
 
+AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[
+AC_TRY_RUN([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() { 
+  struct stat st;
+  char tpl[20]="/tmp/test.XXXXXX"; 
+  int fd = mkstemp(tpl); 
+  if (fd == -1) exit(1);
+  unlink(tpl);
+  if (fstat(fd, &st) != 0) exit(1);
+  if ((st.st_mode & 0777) != 0600) exit(1);
+  exit(0);
+}],
+rsync_cv_HAVE_SECURE_MKSTEMP=yes,
+rsync_cv_HAVE_SECURE_MKSTEMP=no,
+rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
+if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+    AC_DEFINE(HAVE_SECURE_MKSTEMP)
+fi
+
 
 AC_CACHE_CHECK([for broken inet_ntoa],rsync_cv_REPLACE_INET_NTOA,[
 AC_TRY_RUN([
index ef57d90..426eee2 100644 (file)
 {
        size_t len = strlen(s);
        size_t ret = len;
+       if (bufsize <= 0) return 0;
        if (len >= bufsize) len = bufsize-1;
        memcpy(d, s, len);
        d[len] = 0;
index 7be9588..0249d8a 100644 (file)
@@ -304,6 +304,7 @@ 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];
@@ -412,17 +413,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
                        continue;
                }
 
-               /* 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;
-               }
+               strlcpy(template, fnametmp, sizeof(template));
 
                /* we initially set the perms without the
                   setuid/setgid bits to ensure that there is no race
@@ -430,16 +421,21 @@ 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_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
-                             file->mode & INITACCESSPERMS);
+               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;
+               }
 
                /* 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) {
-                       fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
-                                     file->mode & INITACCESSPERMS);
+                       strlcpy(fnametmp, template, sizeof(fnametmp));
+                       fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
                }
                if (fd2 == -1) {
                        rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
index 3780bac..a56eb79 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -113,14 +113,27 @@ int do_mkdir(char *fname, mode_t mode)
        return mkdir(fname, mode);
 }
 
-char *do_mktemp(char *template)
-{
-       if (dry_run) return NULL;
-       if (read_only) {errno = EROFS; return NULL;}
-       
-        /* TODO: Replace this with a good builtin mkstemp, perhaps
-        * from OpenBSD.  Some glibc versions are buggy.  */
-       return mktemp(template);
+/* like mkstemp but forces permissions */
+int do_mkstemp(char *template, mode_t perms)
+{
+       if (dry_run) return -1;
+       if (read_only) {errno = EROFS; return -1;}
+
+#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
+       {
+               int fd = mkstemp(template);
+               if (fd == -1) return -1;
+               if (fchmod(fd, perms) != 0) {
+                       close(fd);
+                       unlink(template);
+                       return -1;
+               }
+               return fd;
+       }
+#else
+       if (!mktemp(template)) return -1;
+       return open(template, O_RDWR|O_EXCL|O_CREAT, perms);
+#endif
 }
 
 int do_stat(const char *fname, STRUCT_STAT *st)