Movemail: allow to copy mailbox ownership when run as root.
* movemail/movemail.c: Implement new configuration keyword "mailbox-ownership" (and the --owner command line option). * doc/texinfo/programs.texi: Document new movemail features. (Ownership): New subsection stub. * NEWS: Update
Showing
3 changed files
with
350 additions
and
124 deletions
1 | GNU mailutils NEWS -- history of user-visible changes. 2009-08-14 | 1 | GNU mailutils NEWS -- history of user-visible changes. 2009-08-20 |
2 | Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, | 2 | Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, |
3 | 2008, 2009 Free Software Foundation, Inc. | 3 | 2008, 2009 Free Software Foundation, Inc. |
4 | See the end of file for copying conditions. | 4 | See the end of file for copying conditions. |
... | @@ -27,6 +27,10 @@ exists in the destination mailbox. | ... | @@ -27,6 +27,10 @@ exists in the destination mailbox. |
27 | The `--verbose' command line option enables outputting additional | 27 | The `--verbose' command line option enables outputting additional |
28 | information. | 28 | information. |
29 | 29 | ||
30 | The `--owner' command line option (and the corresponding | ||
31 | `mailbox-ownership' configuration file statement) copy mailbox | ||
32 | ownership, if the utility is run with root privileges. | ||
33 | |||
30 | 34 | ||
31 | 35 | ||
32 | ** The -f option | 36 | ** The -f option | ... | ... |
... | @@ -4371,13 +4371,15 @@ description of @code{Rmail} interface. | ... | @@ -4371,13 +4371,15 @@ description of @code{Rmail} interface. |
4371 | 4371 | ||
4372 | Mailutils version of @command{movemail} is completely | 4372 | Mailutils version of @command{movemail} is completely |
4373 | backward-compatible with its Emacs predecessor, so it should run | 4373 | backward-compatible with its Emacs predecessor, so it should run |
4374 | flawlessly with older versions of Emacs. Emacs version 21.4, which is | 4374 | flawlessly with older versions of Emacs. Emacs versions |
4375 | being developed at the time of this writing, will contain improved | 4375 | starting from 22.1 contain improved @code{Rmail} interface and |
4376 | @code{Rmail} interface for work with mailutils @command{movemail}. | 4376 | are able to take advantage of all new features mailutils |
4377 | @command{movemail} provides. | ||
4377 | 4378 | ||
4378 | @menu | 4379 | @menu |
4379 | * Movemail Configuration:: | 4380 | * Movemail Configuration:: |
4380 | * Movemail Options:: Description of the Available Options | 4381 | * Movemail Options:: Description of the Available Options |
4382 | * Ownership:: Setting Destination Mailbox Ownership | ||
4381 | * Summary:: Short Movemail Invocation Summary | 4383 | * Summary:: Short Movemail Invocation Summary |
4382 | @end menu | 4384 | @end menu |
4383 | 4385 | ||
... | @@ -4408,6 +4410,31 @@ exists in the destination mailbox. | ... | @@ -4408,6 +4410,31 @@ exists in the destination mailbox. |
4408 | Set verbosity level. | 4410 | Set verbosity level. |
4409 | @end deffn | 4411 | @end deffn |
4410 | 4412 | ||
4413 | @deffn {Movemail Config} mailbox-ownership @var{method-list} | ||
4414 | Define list of methods for setting ownership of the destination | ||
4415 | mailbox. The @var{method-list} argument can contain the following | ||
4416 | elements: | ||
4417 | |||
4418 | @anchor{mailbox-ownership-methods} | ||
4419 | @table @asis | ||
4420 | @item copy-id | ||
4421 | Copy owner UID and GID from the source mailbox. This method works only | ||
4422 | with local mailboxes, i.e.: @samp{mbox} (UNIX mailbox), @samp{maildir} | ||
4423 | and @samp{mh}. | ||
4424 | |||
4425 | @item copy-name | ||
4426 | Get owner name from the source mailbox URL and obtain UID and GID for | ||
4427 | this user using mailutils authorization methods. | ||
4428 | |||
4429 | @item set-id=@var{uid}[:@var{gid}] | ||
4430 | Set supplied @var{uid} and @var{gid}. If @var{gid} is not supplied, | ||
4431 | it is read from the @file{/etc/passwd} record for this UID. | ||
4432 | |||
4433 | @item set-name=@var{user} | ||
4434 | Make destination mailbox owned by @var{user}. | ||
4435 | @end table | ||
4436 | @end deffn | ||
4437 | |||
4411 | @multitable @columnfractions 0.3 0.6 | 4438 | @multitable @columnfractions 0.3 0.6 |
4412 | @headitem Statement @tab Reference | 4439 | @headitem Statement @tab Reference |
4413 | @item debug @tab @xref{Debug Statement}. | 4440 | @item debug @tab @xref{Debug Statement}. |
... | @@ -4439,58 +4466,13 @@ If the remote server supports @acronym{TLS} encryption, use | ... | @@ -4439,58 +4466,13 @@ If the remote server supports @acronym{TLS} encryption, use |
4439 | @option{--tls} to instruct @command{movemail} to initiate encrypted | 4466 | @option{--tls} to instruct @command{movemail} to initiate encrypted |
4440 | connection. | 4467 | connection. |
4441 | 4468 | ||
4442 | Quite a few options control how @command{movemail} handles mail | 4469 | @node Ownership |
4443 | locking (a way of preventing simultaneous access to the source | 4470 | @subsection Setting Destination Mailbox Ownership |
4444 | mailbox). By default, before accessing mailbox @var{file}, | 4471 | @UNREVISED |
4445 | @command{movemail} will first see if the file named | ||
4446 | @file{@var{file}.lock} (so called @dfn{lock file}) exists. If so, it | ||
4447 | will assume that the mailbox is being used by another program and will | ||
4448 | sleep one second. If @file{@var{file}.lock} file disappears after this | ||
4449 | wait period, the program will proceed. Otherwise, it will repeat this | ||
4450 | action ten times. If after ten wait periods the lock file does not | ||
4451 | disappear, @command{movemail} gives up and exits. | ||
4452 | |||
4453 | If the lock file does not exist, @command{movemail} will create it, | ||
4454 | thereby indicating to other programs that the mailbox is being used, | ||
4455 | and will proceed to copying messages to the destination file. When | ||
4456 | finished, @command{movemail} closes the mailbox and removes the lock | ||
4457 | file. | ||
4458 | |||
4459 | Several options control this behavior. To change the default sleep period | ||
4460 | use @option{--lock-retry-timeout}. Its argument is the timeout value | ||
4461 | in seconds. | ||
4462 | |||
4463 | To change number of retries, use @option{--lock-retry-count}. For | ||
4464 | example, setting @code{rmail-movemail-flags} to | ||
4465 | |||
4466 | @smallexample | ||
4467 | --lock-retry-timeout=2 --lock-retry-count=5 | ||
4468 | @end smallexample | ||
4469 | |||
4470 | @noindent | ||
4471 | instructs @command{movemail} to make five attempts to acquire the lock | ||
4472 | file, with two-second intervals between the attempts. | ||
4473 | |||
4474 | You may also force @command{movemail} to remove the lock file if it is | ||
4475 | older than a given amount of time (a so called @dfn{stale lock | ||
4476 | file}). To do so, use the following option: | ||
4477 | |||
4478 | @smallexample | ||
4479 | --lock-expire-timeout=@var{seconds} | ||
4480 | @end smallexample | ||
4481 | |||
4482 | The @option{--lock-expire-timeout} sets the number of seconds after | ||
4483 | which a lock file is considered stale. | ||
4484 | 4472 | ||
4485 | There are special programs that can be used to lock and unlock | ||
4486 | mailboxes. A common example of such programs is @command{dotlock}. If | ||
4487 | you wish to use such @dfn{external locking program} instead of the | ||
4488 | default mailutils locking mechanism, use option | ||
4489 | @option{--external-locker}. Argument to this option specifies the full | ||
4490 | name of the external program to use. | ||
4491 | 4473 | ||
4492 | @node Summary | 4474 | @node Summary |
4493 | @subsection Summary of Movemail Usage | 4475 | @subsection Movemail Usage Summary |
4494 | 4476 | ||
4495 | @smallexample | 4477 | @smallexample |
4496 | movemail [@var{option}...] @var{inbox} @var{destfile} [@var{remote-password}] | 4478 | movemail [@var{option}...] @var{inbox} @var{destfile} [@var{remote-password}] |
... | @@ -4500,7 +4482,7 @@ The first argument, @var{inbox}, is the @acronym{url} (@pxref{URL}) of | ... | @@ -4500,7 +4482,7 @@ The first argument, @var{inbox}, is the @acronym{url} (@pxref{URL}) of |
4500 | the source mailbox. The second argument, @var{destfile}, traditionally | 4482 | the source mailbox. The second argument, @var{destfile}, traditionally |
4501 | means destination file, i.e. the UNIX mailbox to copy messages | 4483 | means destination file, i.e. the UNIX mailbox to copy messages |
4502 | to. However, mailutils @command{movemail} extends the meaning of this | 4484 | to. However, mailutils @command{movemail} extends the meaning of this |
4503 | parameter. You may actually specify any valid @acronym{url} as | 4485 | parameter. You may actually specify any valid @acronym{URL} as |
4504 | @var{destfile} parameter.@footnote{Rmail does not use this | 4486 | @var{destfile} parameter.@footnote{Rmail does not use this |
4505 | feature}. Finally, optional third argument is a traditional way of | 4487 | feature}. Finally, optional third argument is a traditional way of |
4506 | specifying user passwords for remote (@acronym{POP} or @acronym{IMAP}) | 4488 | specifying user passwords for remote (@acronym{POP} or @acronym{IMAP}) |
... | @@ -4521,30 +4503,6 @@ Preserve the source mailbox | ... | @@ -4521,30 +4503,6 @@ Preserve the source mailbox |
4521 | @itemx --reverse | 4503 | @itemx --reverse |
4522 | Reverse the sorting order | 4504 | Reverse the sorting order |
4523 | 4505 | ||
4524 | @item --external-locker=@var{program} | ||
4525 | Use given @var{program} as the external locker program. | ||
4526 | |||
4527 | @item --lock-expire-timeout=@var{seconds} | ||
4528 | Set number of seconds after which the lock expires | ||
4529 | |||
4530 | @item --lock-flags=@var{flags} | ||
4531 | Set locker flags. @var{flags} is composed of the following letters: | ||
4532 | @samp{E} -- use external locker program @command{dotlock}, | ||
4533 | @samp{R} -- retry 10 times if acquiring of the lock failed (see also | ||
4534 | @option{--lock-retry-count} below), @samp{T} -- remove stale locks | ||
4535 | after 10 minutes (see also @option{--lock-expire-timeout}, | ||
4536 | and @samp{P} -- write process @acronym{PID} to the lock file. | ||
4537 | |||
4538 | @item --lock-retry-count=@var{number} | ||
4539 | Set the maximum number of times to retry acquiring the lockfile | ||
4540 | |||
4541 | @item --lock-retry-timeout=@var{seconds} | ||
4542 | Set timeout for acquiring the lockfile | ||
4543 | |||
4544 | @item -m @var{url} | ||
4545 | @itemx --mail-spool @var{URL} | ||
4546 | Use specified URL as a mailspool directory | ||
4547 | |||
4548 | @item --tls[=@var{bool}] | 4506 | @item --tls[=@var{bool}] |
4549 | Enable (default) or disable TLS support | 4507 | Enable (default) or disable TLS support |
4550 | 4508 | ||
... | @@ -4552,6 +4510,13 @@ Enable (default) or disable TLS support | ... | @@ -4552,6 +4510,13 @@ Enable (default) or disable TLS support |
4552 | @item --uidl | 4510 | @item --uidl |
4553 | Use UIDLs to avoid downloading the same message twice. | 4511 | Use UIDLs to avoid downloading the same message twice. |
4554 | 4512 | ||
4513 | @item -P @var{method-list} | ||
4514 | @itemx --owner=@var{method-list} | ||
4515 | Define list of methods for setting ownership of the destination | ||
4516 | mailbox. @xref{mailbox-ownership-methods}, for a description of | ||
4517 | @var{method-list}. This option is useful only when running | ||
4518 | @command{movemail} as root. | ||
4519 | |||
4555 | @item -v | 4520 | @item -v |
4556 | @item --verbose | 4521 | @item --verbose |
4557 | Increase verbosity level. | 4522 | Increase verbosity level. | ... | ... |
... | @@ -24,6 +24,7 @@ | ... | @@ -24,6 +24,7 @@ |
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
27 | #include <pwd.h> | ||
27 | #include <grp.h> | 28 | #include <grp.h> |
28 | #include <unistd.h> | 29 | #include <unistd.h> |
29 | #include <mailutils/mailutils.h> | 30 | #include <mailutils/mailutils.h> |
... | @@ -39,30 +40,74 @@ static char args_doc[] = N_("inbox-url destfile [POP-password]"); | ... | @@ -39,30 +40,74 @@ static char args_doc[] = N_("inbox-url destfile [POP-password]"); |
39 | #define OPT_EMACS 256 | 40 | #define OPT_EMACS 256 |
40 | 41 | ||
41 | static struct argp_option options[] = { | 42 | static struct argp_option options[] = { |
42 | { "preserve", 'p', NULL, 0, N_("Preserve the source mailbox"), 0 }, | 43 | { "preserve", 'p', NULL, 0, N_("Preserve the source mailbox") }, |
43 | { "keep-messages", 0, NULL, OPTION_ALIAS, NULL }, | 44 | { "keep-messages", 0, NULL, OPTION_ALIAS, NULL }, |
44 | { "reverse", 'r', NULL, 0, N_("Reverse the sorting order"), 0 }, | 45 | { "reverse", 'r', NULL, 0, N_("Reverse the sorting order") }, |
45 | { "emacs", OPT_EMACS, NULL, 0, | 46 | { "emacs", OPT_EMACS, NULL, 0, |
46 | N_("Output information used by Emacs rmail interface"), 0 }, | 47 | N_("Output information used by Emacs rmail interface") }, |
47 | { "copy-permissions", 'P', NULL, 0, | ||
48 | N_("Copy original mailbox permissions and ownership when applicable"), | ||
49 | 0 }, | ||
50 | { "uidl", 'u', NULL, 0, | 48 | { "uidl", 'u', NULL, 0, |
51 | N_("Use UIDLs to avoid downloading the same message twice"), | 49 | N_("Use UIDLs to avoid downloading the same message twice") }, |
52 | 0 }, | ||
53 | { "verbose", 'v', NULL, 0, | 50 | { "verbose", 'v', NULL, 0, |
54 | N_("Increase verbosity level"), | 51 | N_("Increase verbosity level") }, |
55 | 0 }, | 52 | { "owner", 'P', N_("MODELIST"), 0, |
53 | N_("Control mailbox ownership") }, | ||
56 | { NULL, 0, NULL, 0, NULL, 0 } | 54 | { NULL, 0, NULL, 0, NULL, 0 } |
57 | }; | 55 | }; |
58 | 56 | ||
59 | static int reverse_order; | 57 | static int reverse_order; |
60 | static int preserve_mail; | 58 | static int preserve_mail; |
61 | static int emacs_mode; | 59 | static int emacs_mode; |
62 | static int copy_meta; | ||
63 | static int uidl_option; | 60 | static int uidl_option; |
64 | static int verbose_option; | 61 | static int verbose_option; |
65 | 62 | ||
63 | enum set_ownership_mode | ||
64 | { | ||
65 | copy_owner_id, | ||
66 | copy_owner_name, | ||
67 | set_owner_id, | ||
68 | set_owner_name | ||
69 | }; | ||
70 | #define SET_OWNERSHIP_MAX 4 | ||
71 | |||
72 | struct user_id | ||
73 | { | ||
74 | uid_t uid; | ||
75 | gid_t gid; | ||
76 | }; | ||
77 | |||
78 | struct set_ownership_method | ||
79 | { | ||
80 | enum set_ownership_mode mode; | ||
81 | union | ||
82 | { | ||
83 | char *name; | ||
84 | struct user_id id; | ||
85 | } owner; | ||
86 | }; | ||
87 | |||
88 | static struct set_ownership_method so_methods[SET_OWNERSHIP_MAX]; | ||
89 | static int so_method_num; | ||
90 | |||
91 | struct set_ownership_method * | ||
92 | get_next_so_method () | ||
93 | { | ||
94 | if (so_method_num == MU_ARRAY_SIZE (so_methods)) | ||
95 | { | ||
96 | mu_error (_("ownership method table overflow")); | ||
97 | exit (1); | ||
98 | } | ||
99 | return so_methods + so_method_num++; | ||
100 | } | ||
101 | |||
102 | mu_kwd_t method_kwd[] = { | ||
103 | { "copy-id", copy_owner_id }, | ||
104 | { "copy-name", copy_owner_name }, | ||
105 | { "set-name", set_owner_name }, | ||
106 | { "user", set_owner_name }, | ||
107 | { "set-id", set_owner_id }, | ||
108 | { NULL } | ||
109 | }; | ||
110 | |||
66 | static error_t | 111 | static error_t |
67 | parse_opt (int key, char *arg, struct argp_state *state) | 112 | parse_opt (int key, char *arg, struct argp_state *state) |
68 | { | 113 | { |
... | @@ -79,7 +124,7 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -79,7 +124,7 @@ parse_opt (int key, char *arg, struct argp_state *state) |
79 | break; | 124 | break; |
80 | 125 | ||
81 | case 'P': | 126 | case 'P': |
82 | copy_meta = 1; | 127 | mu_argp_node_list_new (&lst, "mailbox-ownership", arg); |
83 | break; | 128 | break; |
84 | 129 | ||
85 | case 'u': | 130 | case 'u': |
... | @@ -118,6 +163,130 @@ static struct argp argp = { | ... | @@ -118,6 +163,130 @@ static struct argp argp = { |
118 | }; | 163 | }; |
119 | 164 | ||
120 | 165 | ||
166 | static int | ||
167 | _cb_mailbox_ownership (mu_debug_t debug, const char *str) | ||
168 | { | ||
169 | if (strcmp (str, "clear") == 0) | ||
170 | so_method_num = 0; | ||
171 | else | ||
172 | { | ||
173 | int code; | ||
174 | char *p; | ||
175 | size_t len = strcspn (str, "="); | ||
176 | struct set_ownership_method *meth; | ||
177 | |||
178 | if (mu_kwd_xlat_name_len (method_kwd, str, len, &code)) | ||
179 | { | ||
180 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
181 | _("Invalid ownership method: %s"), | ||
182 | str); | ||
183 | return 1; | ||
184 | } | ||
185 | |||
186 | meth = get_next_so_method (); | ||
187 | meth->mode = code; | ||
188 | switch (meth->mode) | ||
189 | { | ||
190 | case copy_owner_id: | ||
191 | case copy_owner_name: | ||
192 | break; | ||
193 | |||
194 | case set_owner_id: | ||
195 | if (!str[len]) | ||
196 | { | ||
197 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
198 | _("Ownership method %s requires value"), | ||
199 | str); | ||
200 | return 1; | ||
201 | } | ||
202 | str += len + 1; | ||
203 | meth->owner.id.uid = strtoul (str, &p, 0); | ||
204 | if (*p) | ||
205 | { | ||
206 | if (*p == ':') | ||
207 | { | ||
208 | str = p + 1; | ||
209 | meth->owner.id.gid = strtoul (str, &p, 0); | ||
210 | if (*p) | ||
211 | { | ||
212 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
213 | _("expected gid number, but found %s"), | ||
214 | str); | ||
215 | return 1; | ||
216 | } | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
221 | _("expected uid number, but found %s"), | ||
222 | str); | ||
223 | return 1; | ||
224 | } | ||
225 | } | ||
226 | else | ||
227 | meth->owner.id.gid = (gid_t) -1; | ||
228 | break; | ||
229 | |||
230 | case set_owner_name: | ||
231 | if (!str[len]) | ||
232 | { | ||
233 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
234 | _("Ownership method %s requires value"), | ||
235 | str); | ||
236 | return 1; | ||
237 | } | ||
238 | meth->owner.name = mu_strdup (str + len + 1); | ||
239 | } | ||
240 | } | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int | ||
245 | cb_mailbox_ownership (mu_debug_t debug, void *data, mu_config_value_t *val) | ||
246 | { | ||
247 | int i; | ||
248 | |||
249 | if (val->type == MU_CFG_STRING) | ||
250 | { | ||
251 | const char *str = val->v.string; | ||
252 | if (!strchr (str, ',')) | ||
253 | return _cb_mailbox_ownership (debug, str); | ||
254 | else | ||
255 | { | ||
256 | int argc; | ||
257 | char **argv; | ||
258 | |||
259 | if (mu_argcv_get_np (str, strlen (str), ",", NULL, 0, | ||
260 | &argc, &argv, NULL)) | ||
261 | { | ||
262 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
263 | _("cannot parse %s"), | ||
264 | str); | ||
265 | return 1; | ||
266 | } | ||
267 | |||
268 | for (i = 0; i < argc; i++) | ||
269 | if (_cb_mailbox_ownership (debug, argv[i])) | ||
270 | return 1; | ||
271 | |||
272 | mu_argcv_free (argc, argv); | ||
273 | return 0; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if (mu_cfg_assert_value_type (val, MU_CFG_LIST, debug)) | ||
278 | return 1; | ||
279 | |||
280 | for (i = 0; i < val->v.arg.c; i++) | ||
281 | { | ||
282 | if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING, debug)) | ||
283 | return 1; | ||
284 | if (_cb_mailbox_ownership (debug, val->v.arg.v[i].v.string)) | ||
285 | return 1; | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
121 | struct mu_cfg_param movemail_cfg_param[] = { | 290 | struct mu_cfg_param movemail_cfg_param[] = { |
122 | { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, | 291 | { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, |
123 | N_("Do not remove messages from the source mailbox.") }, | 292 | N_("Do not remove messages from the source mailbox.") }, |
... | @@ -128,7 +297,16 @@ struct mu_cfg_param movemail_cfg_param[] = { | ... | @@ -128,7 +297,16 @@ struct mu_cfg_param movemail_cfg_param[] = { |
128 | { "uidl", mu_cfg_bool, &uidl_option, 0, NULL, | 297 | { "uidl", mu_cfg_bool, &uidl_option, 0, NULL, |
129 | N_("Use UIDLs to avoid downloading the same message twice.") }, | 298 | N_("Use UIDLs to avoid downloading the same message twice.") }, |
130 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, | 299 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, |
131 | N_("Increase verbosity level.") }, | 300 | N_("Set verbosity level.") }, |
301 | { "mailbox-ownership", mu_cfg_callback, NULL, 0, | ||
302 | cb_mailbox_ownership, | ||
303 | N_("Define a list of methods for setting mailbox ownership. Valid " | ||
304 | "methods are:\n" | ||
305 | " copy-id get owner UID and GID from the source mailbox\n" | ||
306 | " copy-name get owner name from the source mailbox URL\n" | ||
307 | " set-id=UID[:GID] set supplied UID and GID\n" | ||
308 | " set-name=USER make destination mailbox owned by USER"), | ||
309 | N_("methods: list") }, | ||
132 | { NULL } | 310 | { NULL } |
133 | }; | 311 | }; |
134 | 312 | ||
... | @@ -301,28 +479,17 @@ close_mailboxes (void) | ... | @@ -301,28 +479,17 @@ close_mailboxes (void) |
301 | mu_mailbox_close (source); | 479 | mu_mailbox_close (source); |
302 | } | 480 | } |
303 | 481 | ||
304 | static void | 482 | static int |
305 | set_permissions (mu_mailbox_t mbox) | 483 | get_mbox_owner_id (mu_mailbox_t mbox, mu_url_t url, struct user_id *id) |
306 | { | 484 | { |
307 | mu_url_t url = NULL; | ||
308 | const char *s; | 485 | const char *s; |
309 | int rc; | 486 | int rc = mu_url_sget_scheme (url, &s); |
310 | uid_t uid; | ||
311 | gid_t gid; | ||
312 | |||
313 | if (getuid () != 0) | ||
314 | { | ||
315 | mu_error (_("must be root to use --copy-permissions")); | ||
316 | exit (1); | ||
317 | } | ||
318 | mu_mailbox_get_url (mbox, &url); | ||
319 | rc = mu_url_sget_scheme (url, &s); | ||
320 | if (rc) | 487 | if (rc) |
321 | die (mbox, _("Cannot get scheme"), rc); | 488 | die (mbox, _("Cannot get scheme"), rc); |
322 | if (strcmp (s, "/") == 0 | 489 | if ((strcmp (s, "/") == 0 |
323 | || strcmp (s, "mbox") == 0 | 490 | || strcmp (s, "mbox") == 0 |
324 | || strcmp (s, "mh") == 0 | 491 | || strcmp (s, "mh") == 0 |
325 | || strcmp (s, "maildir") == 0) | 492 | || strcmp (s, "maildir") == 0)) |
326 | { | 493 | { |
327 | struct stat st; | 494 | struct stat st; |
328 | 495 | ||
... | @@ -335,33 +502,124 @@ set_permissions (mu_mailbox_t mbox) | ... | @@ -335,33 +502,124 @@ set_permissions (mu_mailbox_t mbox) |
335 | mu_strerror (errno)); | 502 | mu_strerror (errno)); |
336 | exit (1); | 503 | exit (1); |
337 | } | 504 | } |
338 | uid = st.st_uid; | 505 | id->uid = st.st_uid; |
339 | gid = st.st_gid; | 506 | id->gid = st.st_gid; |
507 | return 0; | ||
340 | } | 508 | } |
341 | else | 509 | else if (verbose_option) |
342 | { | 510 | mu_diag_output (MU_DIAG_WARNING, |
343 | struct mu_auth_data *auth; | 511 | _("ignoring copy-name: not a local mailbox")); |
512 | return 1; | ||
513 | } | ||
344 | 514 | ||
345 | rc = mu_url_sget_user (url, &s); | 515 | static int |
346 | if (rc) | 516 | get_user_id (const char *name, struct user_id *id) |
347 | die (mbox, _("Cannot get user"), rc); | 517 | { |
518 | struct mu_auth_data *auth = mu_get_auth_by_name (name); | ||
348 | 519 | ||
349 | auth = mu_get_auth_by_name (s); | ||
350 | if (!auth) | 520 | if (!auth) |
351 | { | 521 | { |
352 | mu_error (_("No such user: %s"), s); | 522 | if (verbose_option) |
353 | exit (1); | 523 | mu_diag_output (MU_DIAG_WARNING, _("no such user: %s"), name); |
524 | return 1; | ||
354 | } | 525 | } |
526 | |||
527 | id->uid = auth->uid; | ||
528 | id->gid = auth->gid; | ||
529 | mu_auth_data_free (auth); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int | ||
534 | get_mbox_owner_name (mu_mailbox_t mbox, mu_url_t url, struct user_id *id) | ||
535 | { | ||
536 | const char *s; | ||
537 | int rc = mu_url_sget_user (url, &s); | ||
538 | if (rc) | ||
539 | /* FIXME */ | ||
540 | die (mbox, _("Cannot get mailbox owner name"), rc); | ||
541 | |||
542 | return get_user_id (s, id); | ||
543 | } | ||
544 | |||
545 | static int | ||
546 | guess_mbox_owner (mu_mailbox_t mbox, struct user_id *id) | ||
547 | { | ||
548 | mu_url_t url = NULL; | ||
549 | int rc; | ||
550 | struct set_ownership_method *meth; | ||
551 | |||
552 | rc = mu_mailbox_get_url (mbox, &url); | ||
553 | if (rc) | ||
554 | die (mbox, _("Cannot get url"), rc); | ||
555 | |||
556 | rc = 1; | ||
557 | for (meth = so_methods; rc == 1 && meth < so_methods + so_method_num; meth++) | ||
558 | { | ||
559 | switch (meth->mode) | ||
560 | { | ||
561 | case copy_owner_id: | ||
562 | rc = get_mbox_owner_id (mbox, url, id); | ||
563 | break; | ||
564 | |||
565 | case copy_owner_name: | ||
566 | rc = get_mbox_owner_name (mbox, url, id); | ||
567 | break; | ||
568 | |||
569 | case set_owner_id: | ||
570 | id->uid = meth->owner.id.uid; | ||
571 | rc = 0; | ||
572 | if (meth->owner.id.gid == (gid_t)-1) | ||
573 | { | ||
574 | struct passwd *pw = getpwuid (id->uid); | ||
575 | if (pw) | ||
576 | id->gid = pw->pw_gid; | ||
355 | else | 577 | else |
356 | { | 578 | { |
357 | uid = auth->uid; | 579 | if (verbose_option) |
358 | gid = auth->gid; | 580 | mu_diag_output (MU_DIAG_WARNING, |
581 | _("no user with uid %lu found"), | ||
582 | (unsigned long) id->uid); | ||
583 | rc = 1; | ||
584 | } | ||
585 | } | ||
586 | break; | ||
587 | |||
588 | case set_owner_name: | ||
589 | rc = get_user_id (meth->owner.name, id); | ||
590 | break; | ||
359 | } | 591 | } |
360 | mu_auth_data_free (auth); | ||
361 | } | 592 | } |
362 | 593 | ||
363 | if (mu_switch_to_privs (uid, gid, NULL)) | 594 | return rc; |
595 | } | ||
596 | |||
597 | static void | ||
598 | switch_owner (mu_mailbox_t mbox) | ||
599 | { | ||
600 | struct user_id user_id; | ||
601 | |||
602 | if (so_method_num == 0) | ||
603 | return; | ||
604 | |||
605 | if (getuid ()) | ||
606 | { | ||
607 | if (verbose_option) | ||
608 | mu_diag_output (MU_DIAG_WARNING, | ||
609 | _("ignoring mailbox-ownership statement")); | ||
610 | return; | ||
611 | } | ||
612 | |||
613 | if (guess_mbox_owner (mbox, &user_id) == 0) | ||
614 | { | ||
615 | if (mu_switch_to_privs (user_id.uid, user_id.gid, NULL)) | ||
364 | exit (1); | 616 | exit (1); |
617 | } | ||
618 | else | ||
619 | { | ||
620 | mu_error (_("no suitable method for setting mailbox ownership")); | ||
621 | exit (1); | ||
622 | } | ||
365 | } | 623 | } |
366 | 624 | ||
367 | static int | 625 | static int |
... | @@ -443,8 +701,7 @@ main (int argc, char **argv) | ... | @@ -443,8 +701,7 @@ main (int argc, char **argv) |
443 | else | 701 | else |
444 | open_mailbox (&source, source_name, flags, argv[2]); | 702 | open_mailbox (&source, source_name, flags, argv[2]); |
445 | 703 | ||
446 | if (copy_meta) | 704 | switch_owner (source); |
447 | set_permissions (source); | ||
448 | 705 | ||
449 | open_mailbox (&dest, dest_name, MU_STREAM_RDWR | MU_STREAM_CREAT, NULL); | 706 | open_mailbox (&dest, dest_name, MU_STREAM_RDWR | MU_STREAM_CREAT, NULL); |
450 | 707 | ... | ... |
-
Please register or sign in to post a comment