[PATCH v3] cli/insert: add --world-readable flag

Tomi Ollila tomi.ollila at iki.fi
Wed Feb 14 22:08:18 PST 2018


On Thu, Feb 08 2018, Daniel Kahn Gillmor wrote:

> In some cases (e.g. when building a publicly-visible e-mail archive)
> it doesn't make any sense to restrict visibility of the message to the
> current user account.
>
> This adds a --world-readable boolean option for "notmuch insert", so
> that those who want to archive their mail publicly can feed their
> archiver with:
>
>     notmuch insert --world-readable
>
> Other local delivery agents (postfix's local, and dovecot's lda) all
> default to delivery in mode 0600 rather than relying on the user's
> umask, so this fix doesn't change the default.
>
> Also, this does not override the user's umask.  if the umask is
> already set tight, it will not become looser as the result of passing
> --world-readable.

Code looks good to me and tests ... also, +1

testing is too hard atm...

Tomi

>
> Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
> ---
>  doc/man1/notmuch-insert.rst |  6 ++++++
>  notmuch-insert.c            | 25 ++++++++++++++-----------
>  test/T070-insert.sh         | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 65 insertions(+), 11 deletions(-)
>
> diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst
> index 47884515..86e2f567 100644
> --- a/doc/man1/notmuch-insert.rst
> +++ b/doc/man1/notmuch-insert.rst
> @@ -51,6 +51,12 @@ Supported options for **insert** include
>  ``--no-hooks``
>      Prevent hooks from being run.
>  
> +``--world-readable``
> +    When writing mail to the mailbox, allow it to be read by users
> +    other than the current user.  Note that this does not override
> +    umask.  By default, delivered mail is only readable by the current
> +    user.
> +
>  ``--decrypt=(true|nostash|auto|false)``
>      If ``true`` and the message is encrypted, try to decrypt the
>      message while indexing, stashing any session keys discovered.  If
> diff --git a/notmuch-insert.c b/notmuch-insert.c
> index 48490b51..d229c9dc 100644
> --- a/notmuch-insert.c
> +++ b/notmuch-insert.c
> @@ -159,10 +159,10 @@ mkdir_recursive (const void *ctx, const char *path, int mode)
>   * otherwise. Partial results are not cleaned up on errors.
>   */
>  static bool
> -maildir_create_folder (const void *ctx, const char *maildir)
> +maildir_create_folder (const void *ctx, const char *maildir, bool world_readable)
>  {
>      const char *subdirs[] = { "cur", "new", "tmp" };
> -    const int mode = 0700;
> +    const int mode = (world_readable ? 0755 : 0700);
>      char *subdir;
>      unsigned int i;
>  
> @@ -211,10 +211,11 @@ tempfilename (const void *ctx)
>   * is not touched).
>   */
>  static int
> -maildir_mktemp (const void *ctx, const char *maildir, char **path_out)
> +maildir_mktemp (const void *ctx, const char *maildir, bool world_readable, char **path_out)
>  {
>      char *filename, *path;
>      int fd;
> +    const int mode = (world_readable ? 0644 : 0600);
>  
>      do {
>  	filename = tempfilename (ctx);
> @@ -227,7 +228,7 @@ maildir_mktemp (const void *ctx, const char *maildir, char **path_out)
>  	    return -1;
>  	}
>  
> -	fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
> +	fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
>      } while (fd == -1 && errno == EEXIST);
>  
>      if (fd == -1) {
> @@ -289,12 +290,12 @@ copy_fd (int fdout, int fdin)
>   * the file, or NULL on errors.
>   */
>  static char *
> -maildir_write_tmp (const void *ctx, int fdin, const char *maildir)
> +maildir_write_tmp (const void *ctx, int fdin, const char *maildir, bool world_readable)
>  {
>      char *path;
>      int fdout;
>  
> -    fdout = maildir_mktemp (ctx, maildir, &path);
> +    fdout = maildir_mktemp (ctx, maildir, world_readable, &path);
>      if (fdout < 0)
>  	return NULL;
>  
> @@ -323,11 +324,11 @@ FAIL:
>   * errors.
>   */
>  static char *
> -maildir_write_new (const void *ctx, int fdin, const char *maildir)
> +maildir_write_new (const void *ctx, int fdin, const char *maildir, bool world_readable)
>  {
>      char *cleanpath, *tmppath, *newpath, *newdir;
>  
> -    tmppath = maildir_write_tmp (ctx, fdin, maildir);
> +    tmppath = maildir_write_tmp (ctx, fdin, maildir, world_readable);
>      if (! tmppath)
>  	return NULL;
>      cleanpath = tmppath;
> @@ -457,6 +458,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
>      bool create_folder = false;
>      bool keep = false;
>      bool hooks = true;
> +    bool world_readable = false;
>      bool synchronize_flags;
>      char *maildir;
>      char *newpath;
> @@ -467,7 +469,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
>  	{ .opt_string = &folder, .name = "folder", .allow_empty = true },
>  	{ .opt_bool = &create_folder, .name = "create-folder" },
>  	{ .opt_bool = &keep, .name = "keep" },
> -	{ .opt_bool =  &hooks, .name = "hooks" },
> +	{ .opt_bool = &hooks, .name = "hooks" },
> +	{ .opt_bool = &world_readable, .name = "world-readable" },
>  	{ .opt_inherit = notmuch_shared_indexing_options },
>  	{ .opt_inherit = notmuch_shared_options },
>  	{ }
> @@ -523,7 +526,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
>      }
>  
>      strip_trailing (maildir, '/');
> -    if (create_folder && ! maildir_create_folder (config, maildir))
> +    if (create_folder && ! maildir_create_folder (config, maildir, world_readable))
>  	return EXIT_FAILURE;
>  
>      /* Set up our handler for SIGINT. We do not set SA_RESTART so that copying
> @@ -535,7 +538,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
>      sigaction (SIGINT, &action, NULL);
>  
>      /* Write the message to the Maildir new directory. */
> -    newpath = maildir_write_new (config, STDIN_FILENO, maildir);
> +    newpath = maildir_write_new (config, STDIN_FILENO, maildir, world_readable);
>      if (! newpath) {
>  	return EXIT_FAILURE;
>      }
> diff --git a/test/T070-insert.sh b/test/T070-insert.sh
> index 40519bb2..05be473a 100755
> --- a/test/T070-insert.sh
> +++ b/test/T070-insert.sh
> @@ -4,6 +4,10 @@ test_description='"notmuch insert"'
>  
>  test_require_external_prereq gdb
>  
> +# subtests about file permissions assume that we're working with umask
> +# 022 by default.
> +umask 022
> +
>  # Create directories and database before inserting.
>  mkdir -p "$MAIL_DIR"/{cur,new,tmp}
>  mkdir -p "$MAIL_DIR"/Drafts/{cur,new,tmp}
> @@ -37,6 +41,9 @@ notmuch insert < "$gen_msg_filename"
>  cur_msg_filename=$(notmuch search --output=files "subject:insert-subject")
>  test_expect_equal_file "$cur_msg_filename" "$gen_msg_filename"
>  
> +test_begin_subtest "Permissions on inserted message should be 0600"
> +test_expect_equal "600" "$(stat -c %a "$cur_msg_filename")"
> +
>  test_begin_subtest "Insert message adds default tags"
>  output=$(notmuch show --format=json "subject:insert-subject")
>  expected='[[[{
> @@ -73,6 +80,27 @@ notmuch insert +custom < "$gen_msg_filename"
>  output=$(notmuch search --output=messages tag:custom)
>  test_expect_equal "$output" "id:$gen_msg_id"
>  
> +test_begin_subtest "Insert tagged world-readable message"
> +gen_insert_msg
> +notmuch insert --world-readable +world-readable-test < "$gen_msg_filename"
> +cur_msg_filename=$(notmuch search --output=files "tag:world-readable-test")
> +test_expect_equal_file "$cur_msg_filename" "$gen_msg_filename"
> +
> +test_begin_subtest "Permissions on inserted world-readable message should be 0644"
> +test_expect_equal "644" "$(stat -c %a "$cur_msg_filename")"
> +
> +test_begin_subtest "Insert tagged world-readable message with group-only umask"
> +oldumask=$(umask)
> +umask 027
> +gen_insert_msg
> +notmuch insert --world-readable +world-readable-umask-test < "$gen_msg_filename"
> +cur_msg_filename=$(notmuch search --output=files "tag:world-readable-umask-test")
> +umask "$oldumask"
> +test_expect_equal_file "$cur_msg_filename" "$gen_msg_filename"
> +
> +test_begin_subtest "Permissions on inserted world-readable message with funny umask should be 0640"
> +test_expect_equal "640" "$(stat -c %a "$cur_msg_filename")"
> +
>  test_begin_subtest "Insert message, add/remove tags"
>  gen_insert_msg
>  notmuch insert +custom -unread < "$gen_msg_filename"
> @@ -170,6 +198,23 @@ output=$(notmuch search --output=files path:F/G/H/I/J/new tag:folder)
>  basename=$(basename "$output")
>  test_expect_equal_file "$gen_msg_filename" "${MAIL_DIR}/F/G/H/I/J/new/${basename}"
>  
> +test_begin_subtest "Created subfolder should have permissions 0700"
> +test_expect_equal "700" "$(stat -c %a "${MAIL_DIR}/F/G/H/I/J")"
> +test_begin_subtest "Created subfolder new/ should also have permissions 0700"
> +test_expect_equal "700" "$(stat -c %a "${MAIL_DIR}/F/G/H/I/J/new")"
> +
> +test_begin_subtest "Insert message, create world-readable subfolder"
> +gen_insert_msg
> +notmuch insert --folder=F/G/H/I/J/K --create-folder --world-readable +folder-world-readable < "$gen_msg_filename"
> +output=$(notmuch search --output=files path:F/G/H/I/J/K/new tag:folder-world-readable)
> +basename=$(basename "$output")
> +test_expect_equal_file "$gen_msg_filename" "${MAIL_DIR}/F/G/H/I/J/K/new/${basename}"
> +
> +test_begin_subtest "Created world-readable subfolder should have permissions 0755"
> +test_expect_equal "755" "$(stat -c %a "${MAIL_DIR}/F/G/H/I/J/K")"
> +test_begin_subtest "Created world-readable subfolder new/ should also have permissions 0755"
> +test_expect_equal "755" "$(stat -c %a "${MAIL_DIR}/F/G/H/I/J/K/new")"
> +
>  test_begin_subtest "Insert message, create existing subfolder"
>  gen_insert_msg
>  notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename"
> -- 
> 2.15.1
>
> _______________________________________________
> notmuch mailing list
> notmuch at notmuchmail.org
> https://notmuchmail.org/mailman/listinfo/notmuch


More information about the notmuch mailing list