This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU Mailutils".
http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=b9aaf724c6428fb4e0d01950d4d7113671e048e5 The branch, master has been updated via b9aaf724c6428fb4e0d01950d4d7113671e048e5 (commit) via 811b38863c06207ab3012c586176a113c1f8def1 (commit) from 1c0ee63834fc729e6ed49fcfa6965d8a7cc88f87 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b9aaf724c6428fb4e0d01950d4d7113671e048e5 Author: Sergey Poznyakoff <g...@gnu.org.ua> Date: Thu Aug 20 23:39:45 2009 +0300 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 commit 811b38863c06207ab3012c586176a113c1f8def1 Author: Sergey Poznyakoff <g...@gnu.org.ua> Date: Thu Aug 20 23:34:47 2009 +0300 Fix in configure.ac * configure.ac: Use PATH_MAILDIR (without leading underscore). ----------------------------------------------------------------------- Summary of changes: NEWS | 6 +- configure.ac | 2 +- doc/texinfo/programs.texi | 119 +++++---------- movemail/movemail.c | 369 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 361 insertions(+), 135 deletions(-) diff --git a/NEWS b/NEWS index ed4a90e..43b4403 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2009-08-14 +GNU mailutils NEWS -- history of user-visible changes. 2009-08-20 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -27,6 +27,10 @@ exists in the destination mailbox. The `--verbose' command line option enables outputting additional information. +The `--owner' command line option (and the corresponding +`mailbox-ownership' configuration file statement) copy mailbox +ownership, if the utility is run with root privileges. + * Mail ** The -f option diff --git a/configure.ac b/configure.ac index 0258618..f852b92 100644 --- a/configure.ac +++ b/configure.ac @@ -335,7 +335,7 @@ AH_BOTTOM( #ifdef MU_CONF_MAILDIR # define MU_PATH_MAILDIR MU_CONF_MAILDIR #else -# define MU_PATH_MAILDIR _PATH_MAILDIR "/" +# define MU_PATH_MAILDIR PATH_MAILDIR "/" #endif]) use_dbm=no diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi index 4135911..5cf7ef2 100644 --- a/doc/texinfo/programs.texi +++ b/doc/texinfo/programs.texi @@ -4371,13 +4371,15 @@ description of @code{Rmail} interface. Mailutils version of @command{movemail} is completely backward-compatible with its Emacs predecessor, so it should run -flawlessly with older versions of Emacs. Emacs version 21.4, which is -being developed at the time of this writing, will contain improved -...@code{rmail} interface for work with mailutils @command{movemail}. +flawlessly with older versions of Emacs. Emacs versions +starting from 22.1 contain improved @code{Rmail} interface and +are able to take advantage of all new features mailutils +...@command{movemail} provides. @menu * Movemail Configuration:: * Movemail Options:: Description of the Available Options +* Ownership:: Setting Destination Mailbox Ownership * Summary:: Short Movemail Invocation Summary @end menu @@ -4408,6 +4410,31 @@ exists in the destination mailbox. Set verbosity level. @end deffn +...@deffn {Movemail Config} mailbox-ownership @var{method-list} +Define list of methods for setting ownership of the destination +mailbox. The @var{method-list} argument can contain the following +elements: + +...@anchor{mailbox-ownership-methods} +...@table @asis +...@item copy-id +Copy owner UID and GID from the source mailbox. This method works only +with local mailboxes, i.e.: @samp{mbox} (UNIX mailbox), @samp{maildir} +and @samp{mh}. + +...@item copy-name +Get owner name from the source mailbox URL and obtain UID and GID for +this user using mailutils authorization methods. + +...@item set-...@var{uid}[:@var{gid}] +Set supplied @var{uid} and @var{gid}. If @var{gid} is not supplied, +it is read from the @file{/etc/passwd} record for this UID. + +...@item set-na...@var{user} +Make destination mailbox owned by @var{user}. +...@end table +...@end deffn + @multitable @columnfractions 0.3 0.6 @headitem Statement @tab Reference @item debug @tab @xref{Debug Statement}. @@ -4439,58 +4466,13 @@ If the remote server supports @acronym{TLS} encryption, use @option{--tls} to instruct @command{movemail} to initiate encrypted connection. -Quite a few options control how @command{movemail} handles mail -locking (a way of preventing simultaneous access to the source -mailbox). By default, before accessing mailbox @var{file}, -...@command{movemail} will first see if the file named -...@file{@var{file}.lock} (so called @dfn{lock file}) exists. If so, it -will assume that the mailbox is being used by another program and will -sleep one second. If @fi...@var{file}.lock} file disappears after this -wait period, the program will proceed. Otherwise, it will repeat this -action ten times. If after ten wait periods the lock file does not -disappear, @command{movemail} gives up and exits. - -If the lock file does not exist, @command{movemail} will create it, -thereby indicating to other programs that the mailbox is being used, -and will proceed to copying messages to the destination file. When -finished, @command{movemail} closes the mailbox and removes the lock -file. - -Several options control this behavior. To change the default sleep period -use @option{--lock-retry-timeout}. Its argument is the timeout value -in seconds. - -To change number of retries, use @option{--lock-retry-count}. For -example, setting @code{rmail-movemail-flags} to - -...@smallexample ---lock-retry-timeout=2 --lock-retry-count=5 -...@end smallexample - -...@noindent -instructs @command{movemail} to make five attempts to acquire the lock -file, with two-second intervals between the attempts. - -You may also force @command{movemail} to remove the lock file if it is -older than a given amount of time (a so called @dfn{stale lock -file}). To do so, use the following option: - -...@smallexample ---lock-expire-timeo...@var{seconds} -...@end smallexample - -The @option{--lock-expire-timeout} sets the number of seconds after -which a lock file is considered stale. +...@node Ownership +...@subsection Setting Destination Mailbox Ownership +...@unrevised -There are special programs that can be used to lock and unlock -mailboxes. A common example of such programs is @command{dotlock}. If -you wish to use such @dfn{external locking program} instead of the -default mailutils locking mechanism, use option -...@option{--external-locker}. Argument to this option specifies the full -name of the external program to use. @node Summary -...@subsection Summary of Movemail Usage +...@subsection Movemail Usage Summary @smallexample 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 the source mailbox. The second argument, @var{destfile}, traditionally means destination file, i.e. the UNIX mailbox to copy messages to. However, mailutils @command{movemail} extends the meaning of this -parameter. You may actually specify any valid @acronym{url} as +parameter. You may actually specify any valid @acronym{URL} as @var{destfile} paramet...@footnote{rmail does not use this feature}. Finally, optional third argument is a traditional way of specifying user passwords for remote (@acronym{POP} or @acronym{IMAP}) @@ -4521,30 +4503,6 @@ Preserve the source mailbox @itemx --reverse Reverse the sorting order -...@item --external-lock...@var{program} -Use given @var{program} as the external locker program. - -...@item --lock-expire-timeo...@var{seconds} -Set number of seconds after which the lock expires - -...@item --lock-fla...@var{flags} -Set locker flags. @var{flags} is composed of the following letters: -...@samp{e} -- use external locker program @command{dotlock}, -...@samp{r} -- retry 10 times if acquiring of the lock failed (see also -...@option{--lock-retry-count} below), @samp{T} -- remove stale locks -after 10 minutes (see also @option{--lock-expire-timeout}, -and @samp{P} -- write process @acronym{PID} to the lock file. - -...@item --lock-retry-cou...@var{number} -Set the maximum number of times to retry acquiring the lockfile - -...@item --lock-retry-timeo...@var{seconds} -Set timeout for acquiring the lockfile - -...@item -m @var{url} -...@itemx --mail-spool @var{URL} -Use specified URL as a mailspool directory - @item --tl...@var{bool}] Enable (default) or disable TLS support @@ -4552,6 +4510,13 @@ Enable (default) or disable TLS support @item --uidl Use UIDLs to avoid downloading the same message twice. +...@item -P @var{method-list} +...@itemx --own...@var{method-list} +Define list of methods for setting ownership of the destination +mailbox. @xref{mailbox-ownership-methods}, for a description of +...@var{method-list}. This option is useful only when running +...@command{movemail} as root. + @item -v @item --verbose Increase verbosity level. diff --git a/movemail/movemail.c b/movemail/movemail.c index bacfd40..99dc5b0 100644 --- a/movemail/movemail.c +++ b/movemail/movemail.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <pwd.h> #include <grp.h> #include <unistd.h> #include <mailutils/mailutils.h> @@ -39,30 +40,74 @@ static char args_doc[] = N_("inbox-url destfile [POP-password]"); #define OPT_EMACS 256 static struct argp_option options[] = { - { "preserve", 'p', NULL, 0, N_("Preserve the source mailbox"), 0 }, + { "preserve", 'p', NULL, 0, N_("Preserve the source mailbox") }, { "keep-messages", 0, NULL, OPTION_ALIAS, NULL }, - { "reverse", 'r', NULL, 0, N_("Reverse the sorting order"), 0 }, + { "reverse", 'r', NULL, 0, N_("Reverse the sorting order") }, { "emacs", OPT_EMACS, NULL, 0, - N_("Output information used by Emacs rmail interface"), 0 }, - { "copy-permissions", 'P', NULL, 0, - N_("Copy original mailbox permissions and ownership when applicable"), - 0 }, + N_("Output information used by Emacs rmail interface") }, { "uidl", 'u', NULL, 0, - N_("Use UIDLs to avoid downloading the same message twice"), - 0 }, + N_("Use UIDLs to avoid downloading the same message twice") }, { "verbose", 'v', NULL, 0, - N_("Increase verbosity level"), - 0 }, + N_("Increase verbosity level") }, + { "owner", 'P', N_("MODELIST"), 0, + N_("Control mailbox ownership") }, { NULL, 0, NULL, 0, NULL, 0 } }; static int reverse_order; static int preserve_mail; static int emacs_mode; -static int copy_meta; static int uidl_option; static int verbose_option; +enum set_ownership_mode + { + copy_owner_id, + copy_owner_name, + set_owner_id, + set_owner_name + }; +#define SET_OWNERSHIP_MAX 4 + +struct user_id +{ + uid_t uid; + gid_t gid; +}; + +struct set_ownership_method +{ + enum set_ownership_mode mode; + union + { + char *name; + struct user_id id; + } owner; +}; + +static struct set_ownership_method so_methods[SET_OWNERSHIP_MAX]; +static int so_method_num; + +struct set_ownership_method * +get_next_so_method () +{ + if (so_method_num == MU_ARRAY_SIZE (so_methods)) + { + mu_error (_("ownership method table overflow")); + exit (1); + } + return so_methods + so_method_num++; +} + +mu_kwd_t method_kwd[] = { + { "copy-id", copy_owner_id }, + { "copy-name", copy_owner_name }, + { "set-name", set_owner_name }, + { "user", set_owner_name }, + { "set-id", set_owner_id }, + { NULL } +}; + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -79,7 +124,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case 'P': - copy_meta = 1; + mu_argp_node_list_new (&lst, "mailbox-ownership", arg); break; case 'u': @@ -93,7 +138,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case OPT_EMACS: mu_argp_node_list_new (&lst, "emacs", "yes"); break; - + case ARGP_KEY_INIT: mu_argp_node_list_init (&lst); break; @@ -118,6 +163,130 @@ static struct argp argp = { }; +static int +_cb_mailbox_ownership (mu_debug_t debug, const char *str) +{ + if (strcmp (str, "clear") == 0) + so_method_num = 0; + else + { + int code; + char *p; + size_t len = strcspn (str, "="); + struct set_ownership_method *meth; + + if (mu_kwd_xlat_name_len (method_kwd, str, len, &code)) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("Invalid ownership method: %s"), + str); + return 1; + } + + meth = get_next_so_method (); + meth->mode = code; + switch (meth->mode) + { + case copy_owner_id: + case copy_owner_name: + break; + + case set_owner_id: + if (!str[len]) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("Ownership method %s requires value"), + str); + return 1; + } + str += len + 1; + meth->owner.id.uid = strtoul (str, &p, 0); + if (*p) + { + if (*p == ':') + { + str = p + 1; + meth->owner.id.gid = strtoul (str, &p, 0); + if (*p) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("expected gid number, but found %s"), + str); + return 1; + } + } + else + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("expected uid number, but found %s"), + str); + return 1; + } + } + else + meth->owner.id.gid = (gid_t) -1; + break; + + case set_owner_name: + if (!str[len]) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("Ownership method %s requires value"), + str); + return 1; + } + meth->owner.name = mu_strdup (str + len + 1); + } + } + return 0; +} + +static int +cb_mailbox_ownership (mu_debug_t debug, void *data, mu_config_value_t *val) +{ + int i; + + if (val->type == MU_CFG_STRING) + { + const char *str = val->v.string; + if (!strchr (str, ',')) + return _cb_mailbox_ownership (debug, str); + else + { + int argc; + char **argv; + + if (mu_argcv_get_np (str, strlen (str), ",", NULL, 0, + &argc, &argv, NULL)) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("cannot parse %s"), + str); + return 1; + } + + for (i = 0; i < argc; i++) + if (_cb_mailbox_ownership (debug, argv[i])) + return 1; + + mu_argcv_free (argc, argv); + return 0; + } + } + + if (mu_cfg_assert_value_type (val, MU_CFG_LIST, debug)) + return 1; + + for (i = 0; i < val->v.arg.c; i++) + { + if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING, debug)) + return 1; + if (_cb_mailbox_ownership (debug, val->v.arg.v[i].v.string)) + return 1; + } + return 0; +} + struct mu_cfg_param movemail_cfg_param[] = { { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, N_("Do not remove messages from the source mailbox.") }, @@ -128,7 +297,16 @@ struct mu_cfg_param movemail_cfg_param[] = { { "uidl", mu_cfg_bool, &uidl_option, 0, NULL, N_("Use UIDLs to avoid downloading the same message twice.") }, { "verbose", mu_cfg_int, &verbose_option, 0, NULL, - N_("Increase verbosity level.") }, + N_("Set verbosity level.") }, + { "mailbox-ownership", mu_cfg_callback, NULL, 0, + cb_mailbox_ownership, + N_("Define a list of methods for setting mailbox ownership. Valid " + "methods are:\n" + " copy-id get owner UID and GID from the source mailbox\n" + " copy-name get owner name from the source mailbox URL\n" + " set-id=UID[:GID] set supplied UID and GID\n" + " set-name=USER make destination mailbox owned by USER"), + N_("methods: list") }, { NULL } }; @@ -300,29 +478,18 @@ close_mailboxes (void) mu_mailbox_close (dest); mu_mailbox_close (source); } - -static void -set_permissions (mu_mailbox_t mbox) + +static int +get_mbox_owner_id (mu_mailbox_t mbox, mu_url_t url, struct user_id *id) { - mu_url_t url = NULL; const char *s; - int rc; - uid_t uid; - gid_t gid; - - if (getuid () != 0) - { - mu_error (_("must be root to use --copy-permissions")); - exit (1); - } - mu_mailbox_get_url (mbox, &url); - rc = mu_url_sget_scheme (url, &s); + int rc = mu_url_sget_scheme (url, &s); if (rc) die (mbox, _("Cannot get scheme"), rc); - if (strcmp (s, "/") == 0 - || strcmp (s, "mbox") == 0 - || strcmp (s, "mh") == 0 - || strcmp (s, "maildir") == 0) + if ((strcmp (s, "/") == 0 + || strcmp (s, "mbox") == 0 + || strcmp (s, "mh") == 0 + || strcmp (s, "maildir") == 0)) { struct stat st; @@ -335,33 +502,124 @@ set_permissions (mu_mailbox_t mbox) mu_strerror (errno)); exit (1); } - uid = st.st_uid; - gid = st.st_gid; + id->uid = st.st_uid; + id->gid = st.st_gid; + return 0; } - else + else if (verbose_option) + mu_diag_output (MU_DIAG_WARNING, + _("ignoring copy-name: not a local mailbox")); + return 1; +} + +static int +get_user_id (const char *name, struct user_id *id) +{ + struct mu_auth_data *auth = mu_get_auth_by_name (name); + + if (!auth) { - struct mu_auth_data *auth; - - rc = mu_url_sget_user (url, &s); - if (rc) - die (mbox, _("Cannot get user"), rc); - - auth = mu_get_auth_by_name (s); - if (!auth) - { - mu_error (_("No such user: %s"), s); - exit (1); - } - else + if (verbose_option) + mu_diag_output (MU_DIAG_WARNING, _("no such user: %s"), name); + return 1; + } + + id->uid = auth->uid; + id->gid = auth->gid; + mu_auth_data_free (auth); + return 0; +} + +static int +get_mbox_owner_name (mu_mailbox_t mbox, mu_url_t url, struct user_id *id) +{ + const char *s; + int rc = mu_url_sget_user (url, &s); + if (rc) + /* FIXME */ + die (mbox, _("Cannot get mailbox owner name"), rc); + + return get_user_id (s, id); +} + +static int +guess_mbox_owner (mu_mailbox_t mbox, struct user_id *id) +{ + mu_url_t url = NULL; + int rc; + struct set_ownership_method *meth; + + rc = mu_mailbox_get_url (mbox, &url); + if (rc) + die (mbox, _("Cannot get url"), rc); + + rc = 1; + for (meth = so_methods; rc == 1 && meth < so_methods + so_method_num; meth++) + { + switch (meth->mode) { - uid = auth->uid; - gid = auth->gid; + case copy_owner_id: + rc = get_mbox_owner_id (mbox, url, id); + break; + + case copy_owner_name: + rc = get_mbox_owner_name (mbox, url, id); + break; + + case set_owner_id: + id->uid = meth->owner.id.uid; + rc = 0; + if (meth->owner.id.gid == (gid_t)-1) + { + struct passwd *pw = getpwuid (id->uid); + if (pw) + id->gid = pw->pw_gid; + else + { + if (verbose_option) + mu_diag_output (MU_DIAG_WARNING, + _("no user with uid %lu found"), + (unsigned long) id->uid); + rc = 1; + } + } + break; + + case set_owner_name: + rc = get_user_id (meth->owner.name, id); + break; } - mu_auth_data_free (auth); } + + return rc; +} - if (mu_switch_to_privs (uid, gid, NULL)) - exit (1); +static void +switch_owner (mu_mailbox_t mbox) +{ + struct user_id user_id; + + if (so_method_num == 0) + return; + + if (getuid ()) + { + if (verbose_option) + mu_diag_output (MU_DIAG_WARNING, + _("ignoring mailbox-ownership statement")); + return; + } + + if (guess_mbox_owner (mbox, &user_id) == 0) + { + if (mu_switch_to_privs (user_id.uid, user_id.gid, NULL)) + exit (1); + } + else + { + mu_error (_("no suitable method for setting mailbox ownership")); + exit (1); + } } static int @@ -443,8 +701,7 @@ main (int argc, char **argv) else open_mailbox (&source, source_name, flags, argv[2]); - if (copy_meta) - set_permissions (source); + switch_owner (source); open_mailbox (&dest, dest_name, MU_STREAM_RDWR | MU_STREAM_CREAT, NULL); hooks/post-receive -- GNU Mailutils _______________________________________________ Commit-mailutils mailing list Commit-mailutils@gnu.org http://lists.gnu.org/mailman/listinfo/commit-mailutils