X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/f5d0ac07d63bfce83dcf45045b4541fe7a1bca7c..fea9cabd275c3d5809b824a6e4a1446441a6793e:/lib-src/movemail.c
diff --git a/lib-src/movemail.c b/lib-src/movemail.c
index dd3b8291cc..541edf545d 100644
--- a/lib-src/movemail.c
+++ b/lib-src/movemail.c
@@ -1,7 +1,7 @@
/* movemail foo bar -- move file foo to file bar,
locking file foo the way /bin/mail respects.
Copyright (C) 1986, 1992, 1993, 1994, 1996, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -60,6 +60,7 @@ along with GNU Emacs. If not, see . */
#include
#include
#include
+#include
#include
#ifdef HAVE_UNISTD_H
@@ -68,6 +69,9 @@ along with GNU Emacs. If not, see . */
#ifdef HAVE_FCNTL_H
#include
#endif
+#ifdef HAVE_STRING_H
+#include
+#endif
#include "syswait.h"
#ifdef MAIL_USE_POP
#include "pop.h"
@@ -139,36 +143,29 @@ static char *mail_spool_name ();
#endif
#endif
-#ifndef errno
-extern int errno;
-#endif
-char *strerror ();
-#ifdef HAVE_INDEX
-extern char *index __P ((const char *, int));
-#endif
-#ifdef HAVE_RINDEX
-extern char *rindex __P((const char *, int));
+#ifndef HAVE_STRERROR
+char *strerror (int);
#endif
-void fatal ();
-void error ();
-void pfatal_with_name ();
-void pfatal_and_delete ();
-char *concat ();
-long *xmalloc ();
-int popmail ();
-int pop_retr ();
-int mbx_write ();
-int mbx_delimit_begin ();
-int mbx_delimit_end ();
+static void fatal (char *s1, char *s2, char *s3);
+static void error (char *s1, char *s2, char *s3);
+static void pfatal_with_name (char *name);
+static void pfatal_and_delete (char *name);
+static char *concat (char *s1, char *s2, char *s3);
+static long *xmalloc (unsigned int size);
+#ifdef MAIL_USE_POP
+static int popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order);
+static int pop_retr (popserver server, int msgno, FILE *arg);
+static int mbx_write (char *line, int len, FILE *mbf);
+static int mbx_delimit_begin (FILE *mbf);
+static int mbx_delimit_end (FILE *mbf);
+#endif
/* Nonzero means this is name of a lock file to delete on fatal error. */
char *delete_lockname;
int
-main (argc, argv)
- int argc;
- char **argv;
+main (int argc, char **argv)
{
char *inname, *outname;
int indesc, outdesc;
@@ -196,6 +193,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;
@@ -228,7 +228,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", "");
@@ -246,25 +246,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))
{
@@ -276,15 +257,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
@@ -375,10 +353,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
@@ -404,6 +383,9 @@ main (argc, argv)
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:
@@ -497,6 +479,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);
@@ -528,6 +514,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! */
@@ -568,7 +558,7 @@ mail_spool_name (inname)
char *indir, *fname;
int status;
- if (! (fname = rindex (inname, '/')))
+ if (! (fname = strrchr (inname, '/')))
return NULL;
fname++;
@@ -598,9 +588,8 @@ mail_spool_name (inname)
/* Print error message and exit. */
-void
-fatal (s1, s2, s3)
- char *s1, *s2, *s3;
+static void
+fatal (char *s1, char *s2, char *s3)
{
if (delete_lockname)
unlink (delete_lockname);
@@ -611,9 +600,8 @@ fatal (s1, s2, s3)
/* Print error message. `s1' is printf control string, `s2' and `s3'
are args for it or null. */
-void
-error (s1, s2, s3)
- char *s1, *s2, *s3;
+static void
+error (char *s1, char *s2, char *s3)
{
fprintf (stderr, "movemail: ");
if (s3)
@@ -621,20 +609,18 @@ error (s1, s2, s3)
else if (s2)
fprintf (stderr, s1, s2);
else
- fprintf (stderr, s1);
+ fprintf (stderr, "%s", s1);
fprintf (stderr, "\n");
}
-void
-pfatal_with_name (name)
- char *name;
+static void
+pfatal_with_name (char *name)
{
fatal ("%s for %s", strerror (errno), name);
}
-void
-pfatal_and_delete (name)
- char *name;
+static void
+pfatal_and_delete (char *name)
{
char *s = strerror (errno);
unlink (name);
@@ -643,9 +629,8 @@ pfatal_and_delete (name)
/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
+static char *
+concat (char *s1, char *s2, char *s3)
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
@@ -660,9 +645,8 @@ concat (s1, s2, s3)
/* Like malloc but get fatal error if memory is exhausted. */
-long *
-xmalloc (size)
- unsigned size;
+static long *
+xmalloc (unsigned int size)
{
long *result = (long *) malloc (size);
if (!result)
@@ -683,6 +667,7 @@ xmalloc (size)
#include
#endif
#include
+#include
#define NOTOK (-1)
#define OK 0
@@ -710,25 +695,20 @@ char Errmsg[200]; /* POP errors, at least, can exceed
* Return a value suitable for passing to `exit'.
*/
-int
-popmail (mailbox, outfile, preserve, password, reverse_order)
- char *mailbox;
- char *outfile;
- int preserve;
- char *password;
- int reverse_order;
+static int
+popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order)
{
int nmsgs, nbytes;
register int i;
int mbfi;
FILE *mbf;
- char *getenv ();
+ char *getenv (const char *);
popserver server;
int start, end, increment;
char *user, *hostname;
user = mailbox;
- if ((hostname = index(mailbox, ':')))
+ if ((hostname = strchr (mailbox, ':')))
*hostname++ = '\0';
server = pop_open (hostname, user, password, POP_NO_GETPASS);
@@ -841,13 +821,9 @@ popmail (mailbox, outfile, preserve, password, reverse_order)
return EXIT_SUCCESS;
}
-int
-pop_retr (server, msgno, arg)
- popserver server;
- int msgno;
- FILE *arg;
+static int
+pop_retr (popserver server, int msgno, FILE *arg)
{
- extern char *strerror ();
char *line;
int ret;
@@ -892,11 +868,8 @@ pop_retr (server, msgno, arg)
&& (a[3] == 'm') \
&& (a[4] == ' '))
-int
-mbx_write (line, len, mbf)
- char *line;
- int len;
- FILE *mbf;
+static int
+mbx_write (char *line, int len, FILE *mbf)
{
#ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
if (IS_FROM_LINE (line))
@@ -919,20 +892,27 @@ mbx_write (line, len, mbf)
return (OK);
}
-int
-mbx_delimit_begin (mbf)
- FILE *mbf;
+static int
+mbx_delimit_begin (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);
}
-int
-mbx_delimit_end (mbf)
- FILE *mbf;
+static int
+mbx_delimit_end (FILE *mbf)
{
- if (putc ('\037', mbf) == EOF)
+ if (putc ('\n', mbf) == EOF)
return (NOTOK);
return (OK);
}