From 8cb10a4102d1271eeb6d7892a3979ec9ed0beb36 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 15 Aug 2007 14:03:31 +0200 Subject: [PATCH] Use liblockfile, no need for dotlock anymore. Signed-off-by: Pierre Habouzit --- CMakeLists.txt | 10 +- dotlock.c | 634 ---------------------------------------- dotlock.h | 31 -- lib-lua/lua-token.gperf | 1 - lib-lua/madmutt.cpkg | 6 - lib-mx/mx.c | 69 +---- main.c | 5 - 7 files changed, 19 insertions(+), 737 deletions(-) delete mode 100644 dotlock.c delete mode 100644 dotlock.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d393b2..8637b37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,6 @@ SET(CMAKE_MODULE_PATH ${madmutt_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) # TODO {{{ # USE_SETGID -# DOTLOCK_{GROUP,PERMISSION} # }}} INCLUDE(CMakeDetermineCCompiler) @@ -168,6 +167,12 @@ IF(WITH_IDN) SET(HAVE_LIBIDN 1) ENDIF(WITH_IDN) +CHECK_LIBRARY_EXISTS(lockfile lockfile_create "" WITH_LOCKFILE) +IF(NOT WITH_LOCKFILE) + MESSAGE(FATAL_ERROR "lockfile not found") +ENDIF(NOT WITH_LOCKFILE) +SET(MUTTLIBS "${MUTTLIBS} -llockfile") + IF(USE_HCACHE) OPTION(WITH_QDBM "Use qdbm for header caching [default: on]" ON) OPTION(WITH_GDBM "Use gdbm for header caching [default: off]") @@ -317,9 +322,6 @@ ADD_EXECUTABLE(madmutt ${madmuttsrc}) TARGET_LINK_LIBRARIES(madmutt mime sys mx lua imap ui lib) SET_TARGET_PROPERTIES(madmutt PROPERTIES LINK_FLAGS ${MUTTLIBS}) -ADD_EXECUTABLE(madmutt_dotlock dotlock.c) -TARGET_LINK_LIBRARIES(madmutt_dotlock lib) - # generate_files hack {{{ ADD_CUSTOM_COMMAND( diff --git a/dotlock.c b/dotlock.c deleted file mode 100644 index 94f569f..0000000 --- a/dotlock.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Copyright notice from original mutt: - * Copyright (C) 1996-2000 Michael R. Elkins - * Copyright (C) 1998-2000 Thomas Roessler - * - * This file is part of mutt-ng, see http://www.muttng.org/. - * It's licensed under the GNU General Public License, - * please see the file GPL in the top level source directory. - */ - -#include - -#include -#include "dotlock.h" - -#ifdef HAVE_GETOPT_H -#include -#endif - -#define MAXLINKS 1024 /* maximum link depth */ - -# define LONG_STRING 1024 -# define MAXLOCKATTEMPT 5 - -# 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 - -static int DotlockFlags; -static int Retry = MAXLOCKATTEMPT; - -static char *Hostname; - -#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 *, ssize_t, const char *, int fd); -static int dotlock_check_stats (struct stat *, struct stat *); -static int dotlock_dispatch (const char *, int fd); - -static int dotlock_init_privs (void); -static void usage (const char *); - -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 *); - - -#define check_flags(a) \ - if (a & (DL_FL_TRY|DL_FL_UNLOCK|DL_FL_UNLINK)) \ - 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))) - 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 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; -} - - -static int dotlock_dispatch (const char *f, int fd) -{ - char frealpath[_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 (frealpath, sizeof (frealpath), 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 (frealpath); - else if (DotlockFlags & DL_FL_UNLINK) - return dotlock_unlink (frealpath); - else /* lock */ - return dotlock_lock (frealpath); -} - - -/* - * 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 -} - -/* - * Usage information. - * - * This function doesn't return. - * - */ - -static void usage (const char *av0) -{ - fprintf (stderr, "dotlock [Madmutt %s]\n", VERSION); - fprintf (stderr, "usage: %s [-t|-f|-u|-d] [-p] [-r ] 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 \tRetry locking" "\n", stderr); - - exit (DL_EX_ERROR); -} - -/* - * 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_prepare (char *bn, ssize_t l, const char *f, int _fd) -{ - struct stat fsb, lsb; - char frealpath[_POSIX_PATH_MAX]; - char *fbasename, *dirname; - char *p; - int fd; - int r; - - if (dotlock_deference_symlink (frealpath, sizeof (frealpath), f) == -1) - return -1; - - if ((p = strrchr (frealpath, '/'))) { - *p = '\0'; - fbasename = p + 1; - dirname = frealpath; - } - else { - fbasename = frealpath; - dirname = m_strdup("."); - } - - if (m_strlen(fbasename) + 1 > l) - return -1; - - m_strcpy(bn, l, fbasename); - - if (chdir (dirname) == -1) - return -1; - - if (_fd != -1) - fd = _fd; - else if ((fd = open (fbasename, O_RDONLY)) == -1) - return -1; - - r = fstat (fd, &fsb); - - if (_fd == -1) - close (fd); - - if (r == -1) - return -1; - - if (lstat (fbasename, &lsb) == -1) - return -1; - - if (dotlock_check_stats (&fsb, &lsb) == -1) - return -1; - - return 0; -} - -/* - * Expand a symbolic link. - * - * This function expects newpath to have space for - * at least _POSIX_PATH_MAX characters. - * - */ - -static void -dotlock_expand_link (char *newpath, const char *path, const char *flink) -{ - const char *lb = NULL; - size_t len; - - /* link is full path */ - if (*flink == '/') { - m_strcpy(newpath, _POSIX_PATH_MAX, flink); - return; - } - - if ((lb = strrchr (path, '/')) == NULL) { - /* no path in link */ - m_strcpy(newpath, _POSIX_PATH_MAX, flink); - return; - } - - len = lb - path + 1; - memcpy (newpath, path, len); - m_strcpy(newpath + len, _POSIX_PATH_MAX - len, flink); -} - - -/* - * Deference a chain of symbolic links - * - * The final path is written to d. - */ -static int dotlock_deference_symlink (char *d, size_t l, const char *path) -{ - struct stat sb; - char frealpath[_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) { - /* perror (pathptr); */ - return -1; - } - - linkfile[len] = '\0'; - dotlock_expand_link (linkpath, pathptr, linkfile); - m_strcpy(frealpath, sizeof(frealpath), linkpath); - pathptr = frealpath; - } - else - break; - } - - m_strcpy(d, l, pathptr); - return 0; -} - -/* - * 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 - -static int dotlock_lock (const char *frealpath) -{ - char lockfile[_POSIX_PATH_MAX + LONG_STRING]; - char nfslockfile[_POSIX_PATH_MAX + LONG_STRING]; - ssize_t prev_size = 0; - int fd; - int count = 0; - int hard_count = 0; - struct stat sb; - time_t t; - - snprintf (nfslockfile, sizeof (nfslockfile), "%s.%s.%d", - frealpath, Hostname, (int) getpid ()); - snprintf (lockfile, sizeof (lockfile), "%s.lock", frealpath); - - - 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; - } - - - BEGIN_PRIVILEGED (); - } - - END_PRIVILEGED (); - - - close (fd); - - while (hard_count++ < HARDMAXATTEMPTS) { - - BEGIN_PRIVILEGED (); - link (nfslockfile, lockfile); - END_PRIVILEGED (); - - if (stat (nfslockfile, &sb) != 0) { - /* perror ("stat"); */ - return DL_EX_ERROR; - } - - 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. - */ - - t = time (NULL); - do { - sleep (1); - } while (time (NULL) == t); - } - - BEGIN_PRIVILEGED (); - unlink (nfslockfile); - END_PRIVILEGED (); - - return DL_EX_OK; -} - - -/* - * Unlock a file. - * - * The same comment as for dotlock_lock () applies here. - * - */ - -static int dotlock_unlock (const char *frealpath) -{ - char lockfile[_POSIX_PATH_MAX + LONG_STRING]; - int i; - - snprintf (lockfile, sizeof (lockfile), "%s.lock", frealpath); - - BEGIN_PRIVILEGED (); - 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 *frealpath) -{ - struct stat lsb; - int i = -1; - - if (dotlock_lock (frealpath) != DL_EX_OK) - return DL_EX_ERROR; - - if ((i = lstat (frealpath, &lsb)) == 0 && lsb.st_size == 0) - unlink (frealpath); - - dotlock_unlock (frealpath); - - 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 - - return DL_EX_IMPOSSIBLE; -} diff --git a/dotlock.h b/dotlock.h deleted file mode 100644 index 1a41330..0000000 --- a/dotlock.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright notice from original mutt: - * Copyright (C) 1996-2000 Michael R. Elkins - * Copyright (C) 1998-2000 Thomas Roessler - * - * This file is part of mutt-ng, see http://www.muttng.org/. - * It's licensed under the GNU General Public License, - * please see the file GPL in the top level source directory. - */ - -#ifndef _DOTLOCK_H -#define _DOTLOCK_H - -enum dotlock_exits { - DL_EX_OK = 0, - DL_EX_ERROR = 1, - DL_EX_EXIST = 3, - DL_EX_NEED_PRIVS = 4, - DL_EX_IMPOSSIBLE = 5, -}; - -enum dotlock_actions { - DL_FL_TRY = 1 << 0, - DL_FL_UNLOCK = 1 << 1, - DL_FL_USEPRIV = 1 << 2, - DL_FL_FORCE = 1 << 3, - DL_FL_RETRY = 1 << 4, - DL_FL_UNLINK = 1 << 5, -}; - -#endif diff --git a/lib-lua/lua-token.gperf b/lib-lua/lua-token.gperf index b0e47a4..c3857fe 100644 --- a/lib-lua/lua-token.gperf +++ b/lib-lua/lua-token.gperf @@ -127,7 +127,6 @@ exit 0 ## cert_file ## charset ## docdir -## dotlock ## dsn_notify ## dsn_return ## editor diff --git a/lib-lua/madmutt.cpkg b/lib-lua/madmutt.cpkg index dfb04b5..88479db 100644 --- a/lib-lua/madmutt.cpkg +++ b/lib-lua/madmutt.cpkg @@ -161,12 +161,6 @@ static void mod_core_init2(void) */ const string_t hcache_backend = HCACHE_BACKEND; - /* - ** .pp - ** Contains the path of the \fTmadmutt_dotlock(1)\fP binary to be used by - ** Madmutt. - */ - path_t dotlock = m_strdup(BINDIR "/mutt_dotlock"); /* ** .pp ** This variable specifies which editor is used by Madmutt. diff --git a/lib-mx/mx.c b/lib-mx/mx.c index 72f1349..98bd9fa 100644 --- a/lib-mx/mx.c +++ b/lib-mx/mx.c @@ -10,6 +10,8 @@ #include +#include + #include #include #include @@ -27,7 +29,6 @@ #include "keymap.h" #include "compress.h" #include "score.h" -#include "dotlock.h" #include #include "pop.h" @@ -50,66 +51,23 @@ static mx_t const *mxfmts[] = { #define MX_IDX(idx) (idx >= 0 && idx < countof(mxfmts)) #define mutt_is_spool(s) (m_strcmp(Spoolfile, s) == 0) -/* parameters: - * path - file to lock - * retry - should retry if unable to lock? - */ -static int invoke_dotlock (const char *path, int flags, int retry) +static int dotlock_file(const char *path, int retry) { - char cmd[LONG_STRING + _POSIX_PATH_MAX]; - char f[STRING + _POSIX_PATH_MAX]; - char r[STRING]; - - if (flags & DL_FL_RETRY) - snprintf (r, sizeof (r), "-r %d ", retry ? MAXLOCKATTEMPT : 0); - - mutt_quote_filename (f, sizeof (f), path); - - snprintf(cmd, sizeof(cmd), "%s %s%s%s%s%s%s%s", - mod_core.dotlock, - flags & DL_FL_TRY ? "-t " : "", - flags & DL_FL_UNLOCK ? "-u " : "", - flags & DL_FL_USEPRIV ? "-p " : "", - flags & DL_FL_FORCE ? "-f " : "", - flags & DL_FL_UNLINK ? "-d " : "", - flags & DL_FL_RETRY ? r : "", f); - - return mutt_system (cmd); -} + char lockfile[PATH_MAX]; + snprintf(lockfile, sizeof(lockfile), "%s.lock", path); -static int dotlock_file (const char *path, int retry) -{ - int r; - int flags = DL_FL_USEPRIV | DL_FL_RETRY; - - if (retry) - retry = 1; - -retry_lock: - if ((r = invoke_dotlock (path, flags, retry)) == DL_EX_EXIST) { - if (!option (OPTNOCURSES)) { - char msg[LONG_STRING]; - - snprintf (msg, sizeof (msg), - _("Lock count exceeded, remove lock for %s?"), path); - if (retry && mutt_yesorno (msg, M_YES) == M_YES) { - flags |= DL_FL_FORCE; - retry--; - mutt_clear_error (); - goto retry_lock; - } - } - else { - mutt_error (_("Can't dotlock %s.\n"), path); + if (lockfile_create(lockfile, retry ? 1 : 0, 0)) { + if (retry) + mutt_error (_("Can't dotlock %s.\n"), lockfile); } - } - return (r == DL_EX_OK ? 0 : -1); + return 0; } static int undotlock_file (const char *path) { - return (invoke_dotlock (path, DL_FL_USEPRIV | DL_FL_UNLOCK, 0) == - DL_EX_OK ? 0 : -1); + char lockfile[PATH_MAX]; + snprintf(lockfile, sizeof(lockfile), "%s.lock", path); + lockfile_remove(lockfile); } /* looks up index of type for path in mxfmts */ @@ -154,7 +112,6 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int time_out) #ifdef USE_FCNTL struct flock lck; - p_clear(&lck, 1); lck.l_type = excl ? F_WRLCK : F_RDLCK; lck.l_whence = SEEK_SET; @@ -228,7 +185,7 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int time_out) #endif /* USE_FLOCK */ if (r == 0 && dot) - r = dotlock_file (path, time_out); + r = dotlock_file(path, time_out); if (r == -1) { /* release any other locks obtained in this routine */ diff --git a/main.c b/main.c index 885655a..c2d06c5 100644 --- a/main.c +++ b/main.c @@ -138,11 +138,6 @@ static void show_version (void) puts (_("Compile Options:")); puts ( -#ifdef USE_SETGID - " +USE_SETGID" -#else - " -USE_SETGID" -#endif #ifdef USE_FCNTL " +USE_FCNTL" #else -- 2.20.1