Commit 46f1d7b9 46f1d7b9c07df8a5c331e61521114e08b43c7dec by Sam Roberts

Added lock mode MU_LOCK_EXTERNAL which calls an external program to do

the locking. Default is "dotlock", which is setgid mail so can lock in
a mailspool that users may not have write permissions to.
1 parent 5d3c07d1
......@@ -20,16 +20,16 @@
#endif
#include <stdlib.h>
#ifdef __EXT_QNX
# undef __EXT_QNX
#endif
#include <unistd.h>
#include <argp.h>
#include <mailutils/errno.h>
#include <mailutils/locker.h>
#define MU_DL_EX_OK 0
#define MU_DL_EX_ERROR 1
#define MU_DL_EX_EXIST 3
const char *argp_program_version = "GNU dotlock (" PACKAGE ") " VERSION;
const char *argp_program_bug_address = "<bug-mailutils@gnu.org>";
static char doc[] =
......@@ -54,6 +54,9 @@ static struct argp_option options[] = {
{"debug", 'd', NULL, 0,
"Print details of failure reasons to stderr", 0},
{"test", 'T', "PROGRAM", OPTION_HIDDEN,
"Test external dotlocker", 0},
{NULL, 0, NULL, 0, NULL, 0}
};
......@@ -72,6 +75,7 @@ static int flags;
static int retries;
static int force;
static int debug;
static const char *program;
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
......@@ -86,11 +90,18 @@ parse_opt (int key, char *arg, struct argp_state *state)
unlock = 1;
break;
case 'T':
/* This options exists only to test whether internal and external
locking work correctly/the same. */
flags |= MU_LOCKER_EXTERNAL;
program = arg;
break;
case 'r':
if (arg)
{
retries = atoi (arg);
if (retries == 0)
if (retries <= 0)
argp_error (state, "RETRIES must be greater than 0");
}
flags |= MU_LOCKER_RETRY;
......@@ -100,7 +111,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
if (arg)
{
force = atoi (arg);
if (force == 0)
if (force <= 0)
argp_error (state, "MINUTES must be greater than 0");
force *= 60;
}
......@@ -127,6 +138,13 @@ main (int argc, char *argv[])
{
locker_t locker = 0;
int err = 0;
pid_t usergid = getgid();
pid_t mailgid = getegid();
/* Drop permissions during argument parsing. */
if(setegid(usergid) < 0)
return MU_DL_EX_ERROR;
argp_parse (&argp, argc, argv, 0, NULL, NULL);
......@@ -145,11 +163,19 @@ main (int argc, char *argv[])
if (retries != 0)
locker_set_retries (locker, retries);
if (program != 0)
locker_set_external (locker, program);
if(setegid(mailgid) < 0)
return MU_DL_EX_ERROR;
if (unlock)
err = locker_remove_lock (locker);
else
err = locker_lock (locker);
setegid(usergid);
locker_destroy (&locker);
if (debug && err)
......@@ -161,6 +187,12 @@ main (int argc, char *argv[])
case 0:
err = MU_DL_EX_OK;
break;
case EPERM:
err = MU_DL_EX_PERM;
break;
case MU_ERR_LOCK_NOT_HELD:
err = MU_DL_EX_NEXIST;
break;
case MU_ERR_LOCK_CONFLICT:
err = MU_DL_EX_EXIST;
break;
......@@ -171,3 +203,4 @@ main (int argc, char *argv[])
return err;
}
......
......@@ -18,11 +18,8 @@
#ifndef _MAILUTILS_LOCKER_H
#define _MAILUTILS_LOCKER_H
#include <mailutils/mu_features.h>
#include <mailutils/types.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
......@@ -31,12 +28,20 @@ extern "C" {
#define MU_LOCKER_EXPIRE_TIME (10 * 60)
#define MU_LOCKER_RETRIES (10)
#define MU_LOCKER_RETRY_SLEEP (1)
#define MU_LOCKER_EXTERNAL_PROGRAM "dotlock"
/* return codes for the external locker */
#define MU_DL_EX_PERM 4 /* insufficient permissions */
#define MU_DL_EX_EXIST 3 /* lock requested, but file is already locked */
#define MU_DL_EX_NEXIST 2 /* unlock requested, but file is not locked */
#define MU_DL_EX_ERROR 1 /* failed due to some other error */
#define MU_DL_EX_OK 0 /* success */
/* locker_create() flags */
#define MU_LOCKER_NULL 0
/* Special locker type: means no lock. This is to be used with
temporary mailboxes stored in memory. */
#define MU_LOCKER_SIMPLE 0x00
/* Just try and dotlock the file, not the default because its usually
better to retry. */
#define MU_LOCKER_RETRY 0x01
/* This requests that we loop retries times, sleeping retry_sleep
seconds in between trying to obtain the lock before failing with
......@@ -51,6 +56,13 @@ extern "C" {
an external dotlocker, non-setgid programs will use a dotlocker,
which locks and exits imediately. This is a protection against
a server crashing, it's not generally useful. */
#define MU_LOCKER_EXTERNAL 0x08
/* Use an external program to lock the file. This is necessary
for programs having permission to access a file, but do not
have write permission on the directory that contains that file. */
#define MU_LOCKER_NULL 0x10
/* Special locker type: means no lock. This is to be used with
temporary mailboxes stored in memory. */
#define MU_LOCKER_DEFAULT (MU_LOCKER_RETRY)
......@@ -63,11 +75,13 @@ extern int locker_set_flags __P ((locker_t, int));
extern int locker_set_expire_time __P ((locker_t, int));
extern int locker_set_retries __P ((locker_t, int));
extern int locker_set_retry_sleep __P ((locker_t, int));
extern int locker_set_external __P ((locker_t, const char* program));
extern int locker_get_flags __P ((locker_t, int*));
extern int locker_get_expire_time __P ((locker_t, int*));
extern int locker_get_retries __P ((locker_t, int*));
extern int locker_get_retry_sleep __P ((locker_t, int*));
extern int locker_get_external __P ((locker_t, char**));
extern int locker_lock __P ((locker_t));
extern int locker_touchlock __P ((locker_t));
......