Bump version to 23.1.97.
[bpt/emacs.git] / lib-src / movemail.c
index f82bebd..ae51df3 100644 (file)
@@ -1,13 +1,14 @@
 /* movemail foo bar -- move file foo to file bar,
    locking file foo the way /bin/mail respects.
-   Copyright (C) 1986, 92, 93, 94, 96, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1986, 1992, 1993, 1994, 1996, 1999, 2001, 2002, 2003, 2004,
+                 2005, 2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs 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, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,9 +16,8 @@ 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 GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
 
 /* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will
    cause loss of mail* if you do it on a system that does not normally
@@ -54,13 +54,13 @@ Boston, MA 02110-1301, USA.  */
  *
  */
 
-#define NO_SHORTNAMES   /* Tell config not to load remap.h */
 #include <config.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <stdio.h>
 #include <errno.h>
+#include <time.h>
 
 #include <getopt.h>
 #ifdef HAVE_UNISTD_H
@@ -112,7 +112,7 @@ Boston, MA 02110-1301, USA.  */
 #define R_OK 4
 #endif
 
-#if defined (XENIX) || defined (WINDOWSNT)
+#ifdef WINDOWSNT
 #include <sys/locking.h>
 #endif
 
@@ -174,7 +174,7 @@ main (argc, argv)
   char *inname, *outname;
   int indesc, outdesc;
   int nread;
-  WAITTYPE status;
+  int status;
   int c, preserve_mail = 0;
 
 #ifndef MAIL_USE_SYSTEM_LOCK
@@ -197,6 +197,9 @@ main (argc, argv)
 # define ARGSTR "p"
 #endif /* MAIL_USE_POP */
 
+  uid_t real_gid = getgid();
+  uid_t priv_gid = getegid();
+
 #ifdef WINDOWSNT
   /* Ensure all file i/o is in binary mode. */
   _fmode = _O_BINARY;
@@ -229,7 +232,7 @@ main (argc, argv)
       )
     {
 #ifdef MAIL_USE_POP
-      fprintf (stderr, "Usage: movemail [-p] inbox destfile%s\n",
+      fprintf (stderr, "Usage: movemail [-p] [-r] inbox destfile%s\n",
               " [POP-password]");
 #else
       fprintf (stderr, "Usage: movemail [-p] inbox destfile%s\n", "");
@@ -247,25 +250,6 @@ main (argc, argv)
   if (*outname == 0)
     fatal ("Destination file name is empty", 0, 0);
 
-  /* Check access to output file.  */
-  if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
-    pfatal_with_name (outname);
-
-  /* Also check that outname's directory is writable to the real uid.  */
-  {
-    char *buf = (char *) xmalloc (strlen (outname) + 1);
-    char *p;
-    strcpy (buf, outname);
-    p = buf + strlen (buf);
-    while (p > buf && !IS_DIRECTORY_SEP (p[-1]))
-      *--p = 0;
-    if (p == buf)
-      *p++ = '.';
-    if (access (buf, W_OK) != 0)
-      pfatal_with_name (buf);
-    free (buf);
-  }
-
 #ifdef MAIL_USE_POP
   if (!strncmp (inname, "po:", 3))
     {
@@ -277,15 +261,12 @@ main (argc, argv)
       exit (status);
     }
 
-  setuid (getuid ());
+  if (setuid (getuid ()) < 0)
+    fatal ("Failed to drop privileges", 0, 0);
+
 #endif /* MAIL_USE_POP */
 
 #ifndef DISABLE_DIRECT_ACCESS
-
-  /* Check access to input file.  */
-  if (access (inname, R_OK | W_OK) != 0)
-    pfatal_with_name (inname);
-
 #ifndef MAIL_USE_MMDF
 #ifndef MAIL_USE_SYSTEM_LOCK
 #ifdef MAIL_USE_MAILLOCK
@@ -342,6 +323,13 @@ main (argc, argv)
          close (desc);
 
          tem = link (tempname, lockname);
+
+#ifdef EPERM
+         if (tem < 0 && errno == EPERM)
+           fatal ("Unable to create hard link between %s and %s",
+                  tempname, lockname);
+#endif
+
          unlink (tempname);
          if (tem >= 0)
            break;
@@ -369,10 +357,11 @@ main (argc, argv)
       int lockcount = 0;
       int status = 0;
 #if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
-      long touched_lock, now;
+      time_t touched_lock, now;
 #endif
 
-      setuid (getuid ());
+      if (setuid (getuid ()) < 0 || setegid (real_gid) < 0)
+       fatal ("Failed to drop privileges", 0, 0);
 
 #ifndef MAIL_USE_MMDF
 #ifdef MAIL_USE_SYSTEM_LOCK
@@ -387,17 +376,20 @@ main (argc, argv)
       if (indesc < 0)
        pfatal_with_name (inname);
 
-#if defined (BSD_SYSTEM) || defined (XENIX)
+#ifdef BSD_SYSTEM
       /* In case movemail is setuid to root, make sure the user can
         read the output file.  */
       /* This is desirable for all systems
         but I don't want to assume all have the umask system call */
       umask (umask (0) & 0333);
-#endif /* BSD_SYSTEM || XENIX */
+#endif /* BSD_SYSTEM */
       outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
       if (outdesc < 0)
        pfatal_with_name (outname);
 
+      if (setegid (priv_gid) < 0)
+       fatal ("Failed to regain privileges", 0, 0);
+
       /* This label exists so we can retry locking
         after a delay, if it got EAGAIN or EBUSY.  */
     retry_lock:
@@ -421,15 +413,11 @@ main (argc, argv)
 #ifdef MAIL_USE_LOCKF
          status = lockf (indesc, F_LOCK, 0);
 #else /* not MAIL_USE_LOCKF */
-#ifdef XENIX
-         status = locking (indesc, LK_RLCK, 0L);
-#else
 #ifdef WINDOWSNT
          status = locking (indesc, LK_RLCK, -1L);
 #else
          status = flock (indesc, LOCK_EX);
 #endif
-#endif
 #endif /* not MAIL_USE_LOCKF */
 #endif /* MAIL_USE_SYSTEM_LOCK */
        }
@@ -465,6 +453,8 @@ main (argc, argv)
        while (1)
          {
            nread = read (indesc, buf, sizeof buf);
+           if (nread < 0)
+             pfatal_with_name (inname);
            if (nread != write (outdesc, buf, nread))
              {
                int saved_errno = errno;
@@ -493,6 +483,10 @@ main (argc, argv)
        pfatal_and_delete (outname);
 #endif
 
+      /* Prevent symlink attacks truncating other users' mailboxes */
+      if (setegid (real_gid) < 0)
+       fatal ("Failed to drop privileges", 0, 0);
+
       /* Check to make sure no errors before we zap the inbox.  */
       if (close (outdesc) != 0)
        pfatal_and_delete (outname);
@@ -500,13 +494,7 @@ main (argc, argv)
 #ifdef MAIL_USE_SYSTEM_LOCK
       if (! preserve_mail)
        {
-#if defined (STRIDE) || defined (XENIX)
-         /* Stride, xenix have file locking, but no ftruncate.
-            This mess will do. */
-         close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
-#else
          ftruncate (indesc, 0L);
-#endif /* STRIDE or XENIX */
        }
 #endif /* MAIL_USE_SYSTEM_LOCK */
 
@@ -530,6 +518,10 @@ main (argc, argv)
        }
 #endif /* not MAIL_USE_SYSTEM_LOCK */
 
+      /* End of mailbox truncation */
+      if (setegid (priv_gid) < 0)
+       fatal ("Failed to regain privileges", 0, 0);
+
 #ifdef MAIL_USE_MAILLOCK
       /* This has to occur in the child, i.e., in the process that
          acquired the lock! */
@@ -685,6 +677,7 @@ xmalloc (size)
 #include <winsock.h>
 #endif
 #include <pwd.h>
+#include <string.h>
 
 #define NOTOK (-1)
 #define OK 0
@@ -699,7 +692,7 @@ char Errmsg[200];           /* POP errors, at least, can exceed
                                   the original length of 80.  */
 
 /*
- * The full legal syntax for a POP mailbox specification for movemail
+ * The full valid syntax for a POP mailbox specification for movemail
  * is "po:username:hostname".  The ":hostname" is optional; if it is
  * omitted, the MAILHOST environment variable will be consulted.  Note
  * that by the time popmail() is called the "po:" has been stripped
@@ -925,7 +918,16 @@ int
 mbx_delimit_begin (mbf)
      FILE *mbf;
 {
-  if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
+  time_t now;
+  struct tm *ltime;
+  char fromline[40] = "From movemail ";
+
+  now = time (NULL);
+  ltime = localtime (&now);
+
+  strcat (fromline, asctime (ltime));
+
+  if (fputs (fromline, mbf) == EOF)
     return (NOTOK);
   return (OK);
 }
@@ -934,7 +936,7 @@ int
 mbx_delimit_end (mbf)
      FILE *mbf;
 {
-  if (putc ('\037', mbf) == EOF)
+  if (putc ('\n', mbf) == EOF)
     return (NOTOK);
   return (OK);
 }