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 @@ ...@@ -20,16 +20,16 @@
20 #endif 20 #endif
21 21
22 #include <stdlib.h> 22 #include <stdlib.h>
23 #ifdef __EXT_QNX
24 # undef __EXT_QNX
25 #endif
26 #include <unistd.h>
23 27
24 #include <argp.h> 28 #include <argp.h>
25 29
26 #include <mailutils/errno.h> 30 #include <mailutils/errno.h>
27 #include <mailutils/locker.h> 31 #include <mailutils/locker.h>
28 32
29 #define MU_DL_EX_OK 0
30 #define MU_DL_EX_ERROR 1
31 #define MU_DL_EX_EXIST 3
32
33 const char *argp_program_version = "GNU dotlock (" PACKAGE ") " VERSION; 33 const char *argp_program_version = "GNU dotlock (" PACKAGE ") " VERSION;
34 const char *argp_program_bug_address = "<bug-mailutils@gnu.org>"; 34 const char *argp_program_bug_address = "<bug-mailutils@gnu.org>";
35 static char doc[] = 35 static char doc[] =
...@@ -54,6 +54,9 @@ static struct argp_option options[] = { ...@@ -54,6 +54,9 @@ static struct argp_option options[] = {
54 {"debug", 'd', NULL, 0, 54 {"debug", 'd', NULL, 0,
55 "Print details of failure reasons to stderr", 0}, 55 "Print details of failure reasons to stderr", 0},
56 56
57 {"test", 'T', "PROGRAM", OPTION_HIDDEN,
58 "Test external dotlocker", 0},
59
57 {NULL, 0, NULL, 0, NULL, 0} 60 {NULL, 0, NULL, 0, NULL, 0}
58 }; 61 };
59 62
...@@ -72,6 +75,7 @@ static int flags; ...@@ -72,6 +75,7 @@ static int flags;
72 static int retries; 75 static int retries;
73 static int force; 76 static int force;
74 static int debug; 77 static int debug;
78 static const char *program;
75 79
76 static error_t 80 static error_t
77 parse_opt (int key, char *arg, struct argp_state *state) 81 parse_opt (int key, char *arg, struct argp_state *state)
...@@ -86,11 +90,18 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -86,11 +90,18 @@ parse_opt (int key, char *arg, struct argp_state *state)
86 unlock = 1; 90 unlock = 1;
87 break; 91 break;
88 92
93 case 'T':
94 /* This options exists only to test whether internal and external
95 locking work correctly/the same. */
96 flags |= MU_LOCKER_EXTERNAL;
97 program = arg;
98 break;
99
89 case 'r': 100 case 'r':
90 if (arg) 101 if (arg)
91 { 102 {
92 retries = atoi (arg); 103 retries = atoi (arg);
93 if (retries == 0) 104 if (retries <= 0)
94 argp_error (state, "RETRIES must be greater than 0"); 105 argp_error (state, "RETRIES must be greater than 0");
95 } 106 }
96 flags |= MU_LOCKER_RETRY; 107 flags |= MU_LOCKER_RETRY;
...@@ -100,7 +111,7 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -100,7 +111,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
100 if (arg) 111 if (arg)
101 { 112 {
102 force = atoi (arg); 113 force = atoi (arg);
103 if (force == 0) 114 if (force <= 0)
104 argp_error (state, "MINUTES must be greater than 0"); 115 argp_error (state, "MINUTES must be greater than 0");
105 force *= 60; 116 force *= 60;
106 } 117 }
...@@ -127,6 +138,13 @@ main (int argc, char *argv[]) ...@@ -127,6 +138,13 @@ main (int argc, char *argv[])
127 { 138 {
128 locker_t locker = 0; 139 locker_t locker = 0;
129 int err = 0; 140 int err = 0;
141 pid_t usergid = getgid();
142 pid_t mailgid = getegid();
143
144 /* Drop permissions during argument parsing. */
145
146 if(setegid(usergid) < 0)
147 return MU_DL_EX_ERROR;
130 148
131 argp_parse (&argp, argc, argv, 0, NULL, NULL); 149 argp_parse (&argp, argc, argv, 0, NULL, NULL);
132 150
...@@ -145,11 +163,19 @@ main (int argc, char *argv[]) ...@@ -145,11 +163,19 @@ main (int argc, char *argv[])
145 if (retries != 0) 163 if (retries != 0)
146 locker_set_retries (locker, retries); 164 locker_set_retries (locker, retries);
147 165
166 if (program != 0)
167 locker_set_external (locker, program);
168
169 if(setegid(mailgid) < 0)
170 return MU_DL_EX_ERROR;
171
148 if (unlock) 172 if (unlock)
149 err = locker_remove_lock (locker); 173 err = locker_remove_lock (locker);
150 else 174 else
151 err = locker_lock (locker); 175 err = locker_lock (locker);
152 176
177 setegid(usergid);
178
153 locker_destroy (&locker); 179 locker_destroy (&locker);
154 180
155 if (debug && err) 181 if (debug && err)
...@@ -161,6 +187,12 @@ main (int argc, char *argv[]) ...@@ -161,6 +187,12 @@ main (int argc, char *argv[])
161 case 0: 187 case 0:
162 err = MU_DL_EX_OK; 188 err = MU_DL_EX_OK;
163 break; 189 break;
190 case EPERM:
191 err = MU_DL_EX_PERM;
192 break;
193 case MU_ERR_LOCK_NOT_HELD:
194 err = MU_DL_EX_NEXIST;
195 break;
164 case MU_ERR_LOCK_CONFLICT: 196 case MU_ERR_LOCK_CONFLICT:
165 err = MU_DL_EX_EXIST; 197 err = MU_DL_EX_EXIST;
166 break; 198 break;
...@@ -171,3 +203,4 @@ main (int argc, char *argv[]) ...@@ -171,3 +203,4 @@ main (int argc, char *argv[])
171 203
172 return err; 204 return err;
173 } 205 }
206
......
...@@ -18,11 +18,8 @@ ...@@ -18,11 +18,8 @@
18 #ifndef _MAILUTILS_LOCKER_H 18 #ifndef _MAILUTILS_LOCKER_H
19 #define _MAILUTILS_LOCKER_H 19 #define _MAILUTILS_LOCKER_H
20 20
21 #include <mailutils/mu_features.h>
22 #include <mailutils/types.h> 21 #include <mailutils/types.h>
23 22
24 #include <sys/types.h>
25
26 #ifdef __cplusplus 23 #ifdef __cplusplus
27 extern "C" { 24 extern "C" {
28 #endif 25 #endif
...@@ -31,12 +28,20 @@ extern "C" { ...@@ -31,12 +28,20 @@ extern "C" {
31 #define MU_LOCKER_EXPIRE_TIME (10 * 60) 28 #define MU_LOCKER_EXPIRE_TIME (10 * 60)
32 #define MU_LOCKER_RETRIES (10) 29 #define MU_LOCKER_RETRIES (10)
33 #define MU_LOCKER_RETRY_SLEEP (1) 30 #define MU_LOCKER_RETRY_SLEEP (1)
31 #define MU_LOCKER_EXTERNAL_PROGRAM "dotlock"
32
33 /* return codes for the external locker */
34 #define MU_DL_EX_PERM 4 /* insufficient permissions */
35 #define MU_DL_EX_EXIST 3 /* lock requested, but file is already locked */
36 #define MU_DL_EX_NEXIST 2 /* unlock requested, but file is not locked */
37 #define MU_DL_EX_ERROR 1 /* failed due to some other error */
38 #define MU_DL_EX_OK 0 /* success */
34 39
35 /* locker_create() flags */ 40 /* locker_create() flags */
36 41
37 #define MU_LOCKER_NULL 0 42 #define MU_LOCKER_SIMPLE 0x00
38 /* Special locker type: means no lock. This is to be used with 43 /* Just try and dotlock the file, not the default because its usually
39 temporary mailboxes stored in memory. */ 44 better to retry. */
40 #define MU_LOCKER_RETRY 0x01 45 #define MU_LOCKER_RETRY 0x01
41 /* This requests that we loop retries times, sleeping retry_sleep 46 /* This requests that we loop retries times, sleeping retry_sleep
42 seconds in between trying to obtain the lock before failing with 47 seconds in between trying to obtain the lock before failing with
...@@ -51,6 +56,13 @@ extern "C" { ...@@ -51,6 +56,13 @@ extern "C" {
51 an external dotlocker, non-setgid programs will use a dotlocker, 56 an external dotlocker, non-setgid programs will use a dotlocker,
52 which locks and exits imediately. This is a protection against 57 which locks and exits imediately. This is a protection against
53 a server crashing, it's not generally useful. */ 58 a server crashing, it's not generally useful. */
59 #define MU_LOCKER_EXTERNAL 0x08
60 /* Use an external program to lock the file. This is necessary
61 for programs having permission to access a file, but do not
62 have write permission on the directory that contains that file. */
63 #define MU_LOCKER_NULL 0x10
64 /* Special locker type: means no lock. This is to be used with
65 temporary mailboxes stored in memory. */
54 66
55 #define MU_LOCKER_DEFAULT (MU_LOCKER_RETRY) 67 #define MU_LOCKER_DEFAULT (MU_LOCKER_RETRY)
56 68
...@@ -63,11 +75,13 @@ extern int locker_set_flags __P ((locker_t, int)); ...@@ -63,11 +75,13 @@ extern int locker_set_flags __P ((locker_t, int));
63 extern int locker_set_expire_time __P ((locker_t, int)); 75 extern int locker_set_expire_time __P ((locker_t, int));
64 extern int locker_set_retries __P ((locker_t, int)); 76 extern int locker_set_retries __P ((locker_t, int));
65 extern int locker_set_retry_sleep __P ((locker_t, int)); 77 extern int locker_set_retry_sleep __P ((locker_t, int));
78 extern int locker_set_external __P ((locker_t, const char* program));
66 79
67 extern int locker_get_flags __P ((locker_t, int*)); 80 extern int locker_get_flags __P ((locker_t, int*));
68 extern int locker_get_expire_time __P ((locker_t, int*)); 81 extern int locker_get_expire_time __P ((locker_t, int*));
69 extern int locker_get_retries __P ((locker_t, int*)); 82 extern int locker_get_retries __P ((locker_t, int*));
70 extern int locker_get_retry_sleep __P ((locker_t, int*)); 83 extern int locker_get_retry_sleep __P ((locker_t, int*));
84 extern int locker_get_external __P ((locker_t, char**));
71 85
72 extern int locker_lock __P ((locker_t)); 86 extern int locker_lock __P ((locker_t));
73 extern int locker_touchlock __P ((locker_t)); 87 extern int locker_touchlock __P ((locker_t));
......