commit 21d8effb2075ea03b6b9e981f0b244b0cd619291
parent ac1db640d12fb50cc98c6bf492446d98c1ac7a78
Author: parazyd <parazyd@dyne.org>
Date: Sun, 8 Oct 2017 18:18:56 +0200
remove cruft from dotlock.c
Diffstat:
M | src/dotlock.c | | | 626 | +++++++++++++++++-------------------------------------------------------------- |
D | src/dotlock.h | | | 46 | ---------------------------------------------- |
2 files changed, 130 insertions(+), 542 deletions(-)
diff --git a/src/dotlock.c b/src/dotlock.c
@@ -1,33 +1,22 @@
/*
* Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
* Copyright (C) 1998-2001,2007 Thomas Roessler <roessler@does-not-exist.org>
- *
- * This program 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 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/*
- * This module either be compiled into Mutt, or it can be
- * built as a separate program. For building it
- * separately, define the DL_STANDALONE preprocessor
- * macro.
+ * Copyright (C) 2017 Ivan J. <parazyd@dyne.org>
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -46,396 +35,138 @@
#include <limits.h>
#endif
-#include "dotlock.h"
-
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#define VERSION "jaromail"
-#define ReleaseDate "29Nov2014"
-
-/* #ifdef DL_STANDALONE */
-/* # include "reldate.h" */
-/* #endif */
-
#define MAXLINKS 1024 /* maximum link depth */
+#define LONG_STRING 1024
+#define MAXLOCKATTEMPT 5
-#ifdef DL_STANDALONE
+#define strfcpy(A,B,C) strncpy (A,B,C), *(A+(C)-1)=0
-# define LONG_STRING 1024
-# define MAXLOCKATTEMPT 5
-
-# define strfcpy(A,B,C) strncpy (A,B,C), *(A+(C)-1)=0
-
-# ifdef USE_SETGID
-
-# ifdef HAVE_SETEGID
-# define SETEGID setegid
-# else
-# define SETEGID setgid
-# endif
-# ifndef S_ISLNK
-# define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
-# endif
-
-# endif
-
-# ifndef HAVE_SNPRINTF
-extern int snprintf (char *, size_t, const char *, ...);
-# endif
-
-#else /* DL_STANDALONE */
-
-# ifdef USE_SETGID
-# error Do not try to compile dotlock as a mutt module when requiring egid switching!
-# endif
-
-# include "mutt.h"
-# include "mx.h"
-
-#endif /* DL_STANDALONE */
-
-static int DotlockFlags;
-static int Retry = MAXLOCKATTEMPT;
-
-#ifdef DL_STANDALONE
static char *Hostname;
-#endif
-
-#ifdef USE_SETGID
-static gid_t UserGid;
-static gid_t MailGid;
-#endif
static int dotlock_deference_symlink (char *, size_t, const char *);
static int dotlock_prepare (char *, size_t, const char *, int fd);
static int dotlock_check_stats (struct stat *, struct stat *);
static int dotlock_dispatch (const char *, int fd);
-#ifdef DL_STANDALONE
-static int dotlock_init_privs (void);
-static void usage (const char *);
-#endif
-
static void dotlock_expand_link (char *, const char *, const char *);
-static void BEGIN_PRIVILEGED (void);
-static void END_PRIVILEGED (void);
/* These functions work on the current directory.
* Invoke dotlock_prepare () before and check their
* return value.
*/
-static int dotlock_try (void);
static int dotlock_unlock (const char *);
-static int dotlock_unlink (const char *);
static int dotlock_lock (const char *);
+int main (int argc, char **argv) {
+ char *p;
+ struct utsname utsname;
-#ifdef DL_STANDALONE
-
-#define check_flags(a) if (a & DL_FL_ACTIONS) usage (argv[0])
-
-int main (int argc, char **argv)
-{
- int i;
- char *p;
- struct utsname utsname;
-
- /* first, drop privileges */
-
- if (dotlock_init_privs () == -1)
- return DL_EX_ERROR;
-
-
- /* determine the system's host name */
-
- uname (&utsname);
- if (!(Hostname = strdup (utsname.nodename))) /* __MEM_CHECKED__ */
- return DL_EX_ERROR;
- if ((p = strchr (Hostname, '.')))
- *p = '\0';
-
-
- /* parse the command line options. */
- DotlockFlags = 0;
-
- while ((i = getopt (argc, argv, "dtfupr:")) != EOF)
- {
- switch (i)
- {
- /* actions, mutually exclusive */
- case 't': check_flags (DotlockFlags); DotlockFlags |= DL_FL_TRY; break;
- case 'd': check_flags (DotlockFlags); DotlockFlags |= DL_FL_UNLINK; break;
- case 'u': check_flags (DotlockFlags); DotlockFlags |= DL_FL_UNLOCK; break;
-
- /* other flags */
- case 'f': DotlockFlags |= DL_FL_FORCE; break;
- case 'p': DotlockFlags |= DL_FL_USEPRIV; break;
- case 'r': DotlockFlags |= DL_FL_RETRY; Retry = atoi (optarg); break;
-
- default: usage (argv[0]);
- }
- }
-
- if (optind == argc || Retry < 0)
- usage (argv[0]);
-
- return dotlock_dispatch (argv[optind], -1);
-}
-
+ /* determine the system's host name */
+ uname (&utsname);
+ if (!(Hostname = strdup (utsname.nodename))) /* __MEM_CHECKED__ */
+ return 1;
+ if ((p = strchr (Hostname, '.')))
+ *p = '\0';
-/*
- * Determine our effective group ID, and drop
- * privileges.
- *
- * Return value:
- *
- * 0 - everything went fine
- * -1 - we couldn't drop privileges.
- *
- */
-
-
-static int
-dotlock_init_privs (void)
-{
-
-# ifdef USE_SETGID
-
- UserGid = getgid ();
- MailGid = getegid ();
-
- if (SETEGID (UserGid) != 0)
- return -1;
-
-# endif
-
- return 0;
-}
-
-
-#else /* DL_STANDALONE */
-
-/*
- * This function is intended to be invoked from within
- * mutt instead of mx.c's invoke_dotlock ().
- */
-
-int dotlock_invoke (const char *path, int fd, int flags, int retry)
-{
- int currdir;
- int r;
-
- DotlockFlags = flags;
-
- if ((currdir = open (".", O_RDONLY)) == -1)
- return DL_EX_ERROR;
-
- if (!(DotlockFlags & DL_FL_RETRY) || retry)
- Retry = MAXLOCKATTEMPT;
- else
- Retry = 0;
-
- r = dotlock_dispatch (path, fd);
-
- fchdir (currdir);
- close (currdir);
-
- return r;
-}
-
-#endif /* DL_STANDALONE */
-
-
-static int dotlock_dispatch (const char *f, int fd)
-{
- char realpath[_POSIX_PATH_MAX];
-
- /* If dotlock_prepare () succeeds [return value == 0],
- * realpath contains the basename of f, and we have
- * successfully changed our working directory to
- * `dirname $f`. Additionally, f has been opened for
- * reading to verify that the user has at least read
- * permissions on that file.
- *
- * For a more detailed explanation of all this, see the
- * lengthy comment below.
- */
-
- if (dotlock_prepare (realpath, sizeof (realpath), f, fd) != 0)
- return DL_EX_ERROR;
-
- /* Actually perform the locking operation. */
-
- if (DotlockFlags & DL_FL_TRY)
- return dotlock_try ();
- else if (DotlockFlags & DL_FL_UNLOCK)
- return dotlock_unlock (realpath);
- else if (DotlockFlags & DL_FL_UNLINK)
- return dotlock_unlink (realpath);
- else /* lock */
- return dotlock_lock (realpath);
-}
-
-
-/*
- * Get privileges
- *
- * This function re-acquires the privileges we may have
- * if the user told us to do so by giving the "-p"
- * command line option.
- *
- * BEGIN_PRIVILEGES () won't return if an error occurs.
- *
- */
-
-static void
-BEGIN_PRIVILEGED (void)
-{
-#ifdef USE_SETGID
- if (DotlockFlags & DL_FL_USEPRIV)
- {
- if (SETEGID (MailGid) != 0)
- {
- /* perror ("setegid"); */
- exit (DL_EX_ERROR);
- }
- }
-#endif
-}
-
-/*
- * Drop privileges
- *
- * This function drops the group privileges we may have.
- *
- * END_PRIVILEGED () won't return if an error occurs.
- *
- */
-
-static void
-END_PRIVILEGED (void)
-{
-#ifdef USE_SETGID
- if (DotlockFlags & DL_FL_USEPRIV)
- {
- if (SETEGID (UserGid) != 0)
- {
- /* perror ("setegid"); */
- exit (DL_EX_ERROR);
- }
- }
-#endif
+ return dotlock_dispatch (argv[1], -1);
}
-#ifdef DL_STANDALONE
-
-/*
- * Usage information.
- *
- * This function doesn't return.
- *
- */
-
-static void
-usage (const char *av0)
-{
- fprintf (stderr, "dotlock [Mutt %s (%s)]\n", VERSION, ReleaseDate);
- fprintf (stderr, "usage: %s [-t|-f|-u|-d] [-p] [-r <retries>] file\n",
- av0);
-
- fputs ("\noptions:"
- "\n -t\t\ttry"
- "\n -f\t\tforce"
- "\n -u\t\tunlock"
- "\n -d\t\tunlink"
- "\n -p\t\tprivileged"
-#ifndef USE_SETGID
- " (ignored)"
-#endif
- "\n -r <retries>\tRetry locking"
- "\n", stderr);
-
- exit (DL_EX_ERROR);
+static int dotlock_dispatch (const char *f, int fd) {
+ char realpath[_POSIX_PATH_MAX];
+
+ /* If dotlock_prepare () succeeds [return value == 0],
+ * realpath contains the basename of f, and we have
+ * successfully changed our working directory to
+ * `dirname $f`. Additionally, f has been opened for
+ * reading to verify that the user has at least read
+ * permissions on that file.
+ *
+ * For a more detailed explanation of all this, see the
+ * lengthy comment below.
+ */
+
+ if (dotlock_prepare (realpath, sizeof (realpath), f, fd) != 0)
+ return 1;
+
+ /* Actually perform the locking operation. */
+ if(strcmp(f, "-u"))
+ return dotlock_unlock (realpath);
+ else /* lock */
+ return dotlock_lock (realpath);
}
-#endif
/*
* Access checking: Let's avoid to lock other users' mail
* spool files if we aren't permitted to read them.
- *
+ *
* Some simple-minded access (2) checking isn't sufficient
* here: The problem is that the user may give us a
* deeply nested path to a file which has the same name
* as the file he wants to lock, but different
* permissions, say, e.g.
* /tmp/lots/of/subdirs/var/spool/mail/root.
- *
+ *
* He may then try to replace /tmp/lots/of/subdirs by a
* symbolic link to / after we have invoked access () to
* check the file's permissions. The lockfile we'd
* create or remove would then actually be
* /var/spool/mail/root.
- *
+ *
* To avoid this attack, we proceed as follows:
- *
+ *
* - First, follow symbolic links a la
* dotlock_deference_symlink ().
- *
+ *
* - get the result's dirname.
- *
+ *
* - chdir to this directory. If you can't, bail out.
- *
+ *
* - try to open the file in question, only using its
* basename. If you can't, bail out.
- *
+ *
* - fstat that file and compare the result to a
* subsequent lstat (only using the basename). If
* the comparison fails, bail out.
- *
+ *
* dotlock_prepare () is invoked from main () directly
* after the command line parsing has been done.
*
* Return values:
- *
+ *
* 0 - Evereything's fine. The program's new current
* directory is the contains the file to be locked.
* The string pointed to by bn contains the name of
* the file to be locked.
- *
+ *
* -1 - Something failed. Don't continue.
- *
+ *
* tlr, Jul 15 1998
*/
-static int
-dotlock_check_stats (struct stat *fsb, struct stat *lsb)
-{
- /* S_ISLNK (fsb->st_mode) should actually be impossible,
- * but we may have mixed up the parameters somewhere.
- * play safe.
- */
-
- if (S_ISLNK (lsb->st_mode) || S_ISLNK (fsb->st_mode))
- return -1;
-
- if ((lsb->st_dev != fsb->st_dev) ||
- (lsb->st_ino != fsb->st_ino) ||
- (lsb->st_mode != fsb->st_mode) ||
- (lsb->st_nlink != fsb->st_nlink) ||
- (lsb->st_uid != fsb->st_uid) ||
- (lsb->st_gid != fsb->st_gid) ||
- (lsb->st_rdev != fsb->st_rdev) ||
- (lsb->st_size != fsb->st_size))
- {
- /* something's fishy */
- return -1;
- }
-
- return 0;
+static int dotlock_check_stats (struct stat *fsb, struct stat *lsb) {
+ /* S_ISLNK (fsb->st_mode) should actually be impossible,
+ * but we may have mixed up the parameters somewhere.
+ * play safe.
+ */
+
+ if (S_ISLNK (lsb->st_mode) || S_ISLNK (fsb->st_mode))
+ return -1;
+
+ if ((lsb->st_dev != fsb->st_dev) ||
+ (lsb->st_ino != fsb->st_ino) ||
+ (lsb->st_mode != fsb->st_mode) ||
+ (lsb->st_nlink != fsb->st_nlink) ||
+ (lsb->st_uid != fsb->st_uid) ||
+ (lsb->st_gid != fsb->st_gid) ||
+ (lsb->st_rdev != fsb->st_rdev) ||
+ (lsb->st_size != fsb->st_size)) {
+ /* something's fishy */
+ return -1;
+ }
+
+ return 0;
}
static int
@@ -447,10 +178,10 @@ dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
char *p;
int fd;
int r;
-
+
if (dotlock_deference_symlink (realpath, sizeof (realpath), f) == -1)
return -1;
-
+
if ((p = strrchr (realpath, '/')))
{
*p = '\0';
@@ -465,9 +196,9 @@ dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
if (strlen (basename) + 1 > l)
return -1;
-
+
strfcpy (bn, basename, l);
-
+
if (chdir (dirname) == -1)
return -1;
@@ -475,15 +206,15 @@ dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
fd = _fd;
else if ((fd = open (basename, O_RDONLY)) == -1)
return -1;
-
+
r = fstat (fd, &fsb);
-
+
if (_fd == -1)
close (fd);
-
+
if (r == -1)
return -1;
-
+
if (lstat (basename, &lsb) == -1)
return -1;
@@ -495,13 +226,13 @@ dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
/*
* Expand a symbolic link.
- *
+ *
* This function expects newpath to have space for
* at least _POSIX_PATH_MAX characters.
*
*/
-static void
+static void
dotlock_expand_link (char *newpath, const char *path, const char *link)
{
const char *lb = NULL;
@@ -529,7 +260,7 @@ dotlock_expand_link (char *newpath, const char *path, const char *link)
/*
* Deference a chain of symbolic links
- *
+ *
* The final path is written to d.
*
*/
@@ -541,31 +272,31 @@ dotlock_deference_symlink (char *d, size_t l, const char *path)
char realpath[_POSIX_PATH_MAX];
const char *pathptr = path;
int count = 0;
-
+
while (count++ < MAXLINKS)
{
if (lstat (pathptr, &sb) == -1)
+ {
+ /* perror (pathptr); */
+ return -1;
+ }
+
+ if (S_ISLNK (sb.st_mode))
+ {
+ char linkfile[_POSIX_PATH_MAX];
+ char linkpath[_POSIX_PATH_MAX];
+ int len;
+
+ if ((len = readlink (pathptr, linkfile, sizeof (linkfile) - 1)) == -1)
{
/* perror (pathptr); */
return -1;
}
-
- if (S_ISLNK (sb.st_mode))
- {
- char linkfile[_POSIX_PATH_MAX];
- char linkpath[_POSIX_PATH_MAX];
- int len;
-
- if ((len = readlink (pathptr, linkfile, sizeof (linkfile) - 1)) == -1)
- {
- /* perror (pathptr); */
- return -1;
- }
-
- linkfile[len] = '\0';
- dotlock_expand_link (linkpath, pathptr, linkfile);
- strfcpy (realpath, linkpath, sizeof (realpath));
- pathptr = realpath;
+
+ linkfile[len] = '\0';
+ dotlock_expand_link (linkpath, pathptr, linkfile);
+ strfcpy (realpath, linkpath, sizeof (realpath));
+ pathptr = realpath;
}
else
break;
@@ -577,11 +308,11 @@ dotlock_deference_symlink (char *d, size_t l, const char *path)
/*
* Dotlock a file.
- *
+ *
* realpath is assumed _not_ to be an absolute path to
* the file we are about to lock. Invoke
* dotlock_prepare () before using this function!
- *
+ *
*/
#define HARDMAXATTEMPTS 10
@@ -591,108 +322,63 @@ dotlock_lock (const char *realpath)
{
char lockfile[_POSIX_PATH_MAX + LONG_STRING];
char nfslockfile[_POSIX_PATH_MAX + LONG_STRING];
- size_t prev_size = 0;
int fd;
- int count = 0;
int hard_count = 0;
struct stat sb;
time_t t;
int i;
snprintf (nfslockfile, sizeof (nfslockfile), "%s.%s.%d",
- realpath, Hostname, (int) getpid ());
+ realpath, Hostname, (int) getpid ());
snprintf (lockfile, sizeof (lockfile), "%s.lock", realpath);
-
- BEGIN_PRIVILEGED ();
-
unlink (nfslockfile);
-
while ((fd = open (nfslockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) < 0)
{
- END_PRIVILEGED ();
-
-
if (errno != EAGAIN)
{
/* perror ("cannot open NFS lock file"); */
- return DL_EX_ERROR;
+ return 1;
}
-
-
- BEGIN_PRIVILEGED ();
}
- END_PRIVILEGED ();
-
-
close (fd);
-
+
while (hard_count++ < HARDMAXATTEMPTS)
{
- BEGIN_PRIVILEGED ();
i = link (nfslockfile, lockfile);
- END_PRIVILEGED ();
if (stat (nfslockfile, &sb) != 0)
{
/* perror ("stat"); */
- return DL_EX_ERROR;
+ return 1;
}
if (sb.st_nlink == 2)
break;
- if (count == 0)
- prev_size = sb.st_size;
-
- if (prev_size == sb.st_size && ++count > Retry)
- {
- if (DotlockFlags & DL_FL_FORCE)
- {
- BEGIN_PRIVILEGED ();
- unlink (lockfile);
- END_PRIVILEGED ();
-
- count = 0;
- continue;
- }
- else
- {
- BEGIN_PRIVILEGED ();
- unlink (nfslockfile);
- END_PRIVILEGED ();
- return DL_EX_EXIST;
- }
- }
-
- prev_size = sb.st_size;
-
/* don't trust sleep (3) as it may be interrupted
- * by users sending signals.
+ * by users sending signals.
*/
-
+
t = time (NULL);
do {
sleep (1);
} while (time (NULL) == t);
}
- BEGIN_PRIVILEGED ();
unlink (nfslockfile);
- END_PRIVILEGED ();
- return DL_EX_OK;
+ return 0;
}
-
/*
- * Unlock a file.
- *
- * The same comment as for dotlock_lock () applies here.
- *
- */
+* Unlock a file.
+*
+* The same comment as for dotlock_lock () applies here.
+*
+*/
static int
dotlock_unlock (const char *realpath)
@@ -700,63 +386,11 @@ dotlock_unlock (const char *realpath)
char lockfile[_POSIX_PATH_MAX + LONG_STRING];
int i;
- snprintf (lockfile, sizeof (lockfile), "%s.lock",
- realpath);
-
- BEGIN_PRIVILEGED ();
+ snprintf (lockfile, sizeof (lockfile), "%s.lock", realpath);
i = unlink (lockfile);
- END_PRIVILEGED ();
-
- if (i == -1)
- return DL_EX_ERROR;
-
- return DL_EX_OK;
-}
-
-/* remove an empty file */
-static int
-dotlock_unlink (const char *realpath)
-{
- struct stat lsb;
- int i = -1;
-
- if (dotlock_lock (realpath) != DL_EX_OK)
- return DL_EX_ERROR;
-
- if ((i = lstat (realpath, &lsb)) == 0 && lsb.st_size == 0)
- unlink (realpath);
-
- dotlock_unlock (realpath);
-
- return (i == 0) ? DL_EX_OK : DL_EX_ERROR;
-}
-
-
-/*
- * Check if a file can be locked at all.
- *
- * The same comment as for dotlock_lock () applies here.
- *
- */
-
-static int
-dotlock_try (void)
-{
-#ifdef USE_SETGID
- struct stat sb;
-#endif
-
- if (access (".", W_OK) == 0)
- return DL_EX_OK;
-
-#ifdef USE_SETGID
- if (stat (".", &sb) == 0)
- {
- if ((sb.st_mode & S_IWGRP) == S_IWGRP && sb.st_gid == MailGid)
- return DL_EX_NEED_PRIVS;
- }
-#endif
+ if (i == -1)
+ return 1;
- return DL_EX_IMPOSSIBLE;
+ return 0;
}
diff --git a/src/dotlock.h b/src/dotlock.h
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
- * Copyright (C) 1998-2000 Thomas Roessler <roessler@does-not-exist.org>
- *
- * This program 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 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _DOTLOCK_H
-#define _DOTLOCK_H
-
-/* exit values */
-
-#define DL_EX_OK 0
-#define DL_EX_ERROR 1
-#define DL_EX_EXIST 3
-#define DL_EX_NEED_PRIVS 4
-#define DL_EX_IMPOSSIBLE 5
-
-/* flags */
-
-#define DL_FL_TRY (1 << 0)
-#define DL_FL_UNLOCK (1 << 1)
-#define DL_FL_USEPRIV (1 << 2)
-#define DL_FL_FORCE (1 << 3)
-#define DL_FL_RETRY (1 << 4)
-#define DL_FL_UNLINK (1 << 5)
-
-#define DL_FL_ACTIONS (DL_FL_TRY|DL_FL_UNLOCK|DL_FL_UNLINK)
-
-#ifndef DL_STANDALONE
-int dotlock_invoke (const char *, int, int, int);
-#endif
-
-#endif