X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/ecae6af979abcbb5b45c33ee05ceb297678ec9a0..fea9cabd275c3d5809b824a6e4a1446441a6793e:/lib-src/movemail.c diff --git a/lib-src/movemail.c b/lib-src/movemail.c index 6d6a8b5188..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 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,41 +143,34 @@ 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; int nread; - WAITTYPE status; + int status; int c, preserve_mail = 0; #ifndef MAIL_USE_SYSTEM_LOCK @@ -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 @@ -341,6 +319,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; @@ -368,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 @@ -397,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: @@ -490,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); @@ -521,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! */ @@ -561,7 +558,7 @@ mail_spool_name (inname) char *indir, *fname; int status; - if (! (fname = rindex (inname, '/'))) + if (! (fname = strrchr (inname, '/'))) return NULL; fname++; @@ -591,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); @@ -604,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) @@ -614,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); @@ -636,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); @@ -653,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) @@ -676,6 +667,7 @@ xmalloc (size) #include #endif #include +#include #define NOTOK (-1) #define OK 0 @@ -703,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); @@ -834,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; @@ -885,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)) @@ -912,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); }