commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-395-gdfed0be


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-395-gdfed0be
Date: Mon, 17 Oct 2011 19:53:57 +0000

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=dfed0be6c0fb0541234422af700e955b77d09bd4

The branch, master has been updated
       via  dfed0be6c0fb0541234422af700e955b77d09bd4 (commit)
      from  502c63533d25a0144b65041f9a164b4090bea37b (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 dfed0be6c0fb0541234422af700e955b77d09bd4
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Oct 17 09:37:10 2011 +0300

    Provide a mechanism for configurable file safety checking.
    
    Use it in maidag (.forward file safety) and in libmu_auth (TLS files).
    
    * include/mailutils/tls.h (mu_tls_module_config): New members
    for safety check flags.
    * include/mailutils/util.h (MU_FILE_SAFETY_NONE,MU_FILE_SAFETY_ALL)
    (MU_FILE_SAFETY_OWNER_MISMATCH)
    (MU_FILE_SAFETY_GROUP_WRITABLE,MU_FILE_SAFETY_WORLD_WRITABLE)
    (MU_FILE_SAFETY_GROUP_READABLE,MU_FILE_SAFETY_WORLD_READABLE)
    (MU_FILE_SAFETY_LINKED_WRDIR)
    (MU_FILE_SAFETY_DIR_IWGRP,MU_FILE_SAFETY_DIR_IWOTH): New constants.
    (mu_file_safety_check,mu_file_safety_name_to_code)
    (mu_file_safety_name_to_error): New protos.
    * libmailutils/base/checkperms.c: New file.
    * libmailutils/base/Makefile.am (libbase_la_SOURCES): Add checkperms.c.
    * libmailutils/diag/errors: Add new error codes.
    (MU_ERR_UNSAFE_PERMS): change description wording.
    * libmu_auth/tls.c (mu_check_tls_environment): Use mu_file_safety_check.
    * libmu_cfg/tls.c (tls_settings): Initialize.
    (mu_tls_param): New configuration file statements:
    key-file-safety-checks, cert-file-safety-checks, ca-file-safety-checks.
    * maidag/forward.c (maidag_forward): Use mu_file_safety_check.
    * maidag/maidag.c (cb2_forward_file_checks): Use
    mu_file_safety_name_to_code.

-----------------------------------------------------------------------

Summary of changes:
 include/mailutils/tls.h        |    6 +
 include/mailutils/util.h       |   29 +++++
 libmailutils/base/Makefile.am  |    1 +
 libmailutils/base/filesafety.c |  253 ++++++++++++++++++++++++++++++++++++++++
 libmailutils/diag/errors       |   14 ++-
 libmu_auth/tls.c               |   47 ++++----
 libmu_cfg/tls.c                |   86 ++++++++++++++-
 maidag/forward.c               |  168 +++------------------------
 maidag/maidag.c                |   45 +++----
 maidag/maidag.h                |    9 --
 10 files changed, 446 insertions(+), 212 deletions(-)
 create mode 100644 libmailutils/base/filesafety.c

diff --git a/include/mailutils/tls.h b/include/mailutils/tls.h
index abaa98e..6fdd49a 100644
--- a/include/mailutils/tls.h
+++ b/include/mailutils/tls.h
@@ -28,9 +28,15 @@ extern "C" {
 struct mu_tls_module_config
 {
   int enable;
+  
   char *ssl_cert;
+  int ssl_cert_safety_checks;
+
   char *ssl_key;
+  int ssl_key_safety_checks;
+  
   char *ssl_cafile;
+  int ssl_cafile_safety_checks;
 };
 
 extern int mu_tls_module_init (enum mu_gocs_op, void *);
diff --git a/include/mailutils/util.h b/include/mailutils/util.h
index 3ea257f..a1d4159 100644
--- a/include/mailutils/util.h
+++ b/include/mailutils/util.h
@@ -199,6 +199,35 @@ void mu_onexit_reset (void);
 /* Register the onexit function and associated data */
 int mu_onexit (mu_onexit_t func, void *data);
 
+#define MU_FILE_SAFETY_NONE           0x00
+#define MU_FILE_SAFETY_OWNER_MISMATCH 0x01
+#define MU_FILE_SAFETY_GROUP_WRITABLE 0x02
+#define MU_FILE_SAFETY_WORLD_WRITABLE 0x04
+#define MU_FILE_SAFETY_GROUP_READABLE 0x08
+#define MU_FILE_SAFETY_WORLD_READABLE 0x10  
+#define MU_FILE_SAFETY_LINKED_WRDIR   0x20 
+#define MU_FILE_SAFETY_DIR_IWGRP      0x40
+#define MU_FILE_SAFETY_DIR_IWOTH      0x80
+
+#define MU_FILE_SAFETY_ALL      (              \
+  MU_FILE_SAFETY_OWNER_MISMATCH |              \
+  MU_FILE_SAFETY_GROUP_WRITABLE |              \
+  MU_FILE_SAFETY_WORLD_WRITABLE |              \
+  MU_FILE_SAFETY_GROUP_READABLE |              \
+  MU_FILE_SAFETY_WORLD_READABLE |              \
+  MU_FILE_SAFETY_LINKED_WRDIR   |              \
+  MU_FILE_SAFETY_DIR_IWGRP      |              \
+  MU_FILE_SAFETY_DIR_IWOTH      )
+  
+
+struct mu_auth_data;
+
+int mu_file_safety_check (const char *filename, int mode,
+                         struct mu_auth_data *auth,
+                         mu_list_t idlist);
+int mu_file_safety_name_to_code (const char *name, int *pcode);
+int mu_file_safety_name_to_error (const char *name, int *pcode);  
+  
 #ifdef __cplusplus
 }
 #endif
diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am
index 592eb7c..96ea2f8 100644
--- a/libmailutils/base/Makefile.am
+++ b/libmailutils/base/Makefile.am
@@ -24,6 +24,7 @@ libbase_la_SOURCES = \
  argcvjoin.c\
  argcvrem.c\
  assoc.c\
+ filesafety.c\
  daemon.c\
  date.c\
  fdwait.c\
diff --git a/libmailutils/base/filesafety.c b/libmailutils/base/filesafety.c
new file mode 100644
index 0000000..5bf2820
--- /dev/null
+++ b/libmailutils/base/filesafety.c
@@ -0,0 +1,253 @@
+/* File safety checks.
+   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2010, 2011
+   Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see 
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/errno.h>
+#include <mailutils/mu_auth.h>
+#include <mailutils/list.h>
+#include <mailutils/util.h>
+
+/* Functions for checking mode of a file and the directory it resides in.
+   Each of these checks certain bits and returns 0 if they are OK
+   and non-0 otherwise. */
+
+struct file_check_buffer
+{
+  struct stat filst;
+  struct stat dirst;
+  int cdir;
+};
+
+static int
+_check_grdfil (struct file_check_buffer *fb)
+{
+  return fb->filst.st_mode & S_IRGRP;
+}
+
+static int
+_check_ardfil (struct file_check_buffer *fb)
+{
+  return fb->filst.st_mode & S_IROTH;
+}
+
+static int
+_check_gwrfil (struct file_check_buffer *fb)
+{
+  return fb->filst.st_mode & S_IWGRP;
+}
+
+static int
+_check_awrfil (struct file_check_buffer *fb)
+{
+  return fb->filst.st_mode & S_IWOTH;
+}
+
+static int
+_check_linkwrdir (struct file_check_buffer *fb)
+{
+  return (fb->filst.st_mode & S_IFLNK) &&
+         (fb->dirst.st_mode & (S_IWGRP | S_IWOTH));
+}
+
+static int
+_check_gwrdir (struct file_check_buffer *fb)
+{
+  return fb->dirst.st_mode & S_IWGRP;
+}
+
+static int
+_check_awrdir (struct file_check_buffer *fb)
+{
+  return fb->dirst.st_mode & S_IWOTH;
+}
+
+/* The table of permission checkers below has this type: */
+struct safety_checker
+{
+  char *name;            /* Symbolic name */
+  int flag;              /* MU_FILE_SAFETY_ flag that enables this entry */
+  int err;               /* Corresponding error code */
+  int cdir;              /* True if the function needs dirst member */
+  int (*fun) (struct file_check_buffer *fb); /* Checker function */
+};
+
+static struct safety_checker file_safety_check_tab[] = {
+  { "grdfil", MU_FILE_SAFETY_GROUP_READABLE, MU_ERR_PERM_GROUP_READABLE,
+    0, _check_grdfil },
+  { "ardfil", MU_FILE_SAFETY_WORLD_READABLE, MU_ERR_PERM_WORLD_READABLE,
+    0, _check_ardfil },
+  { "gwrfil", MU_FILE_SAFETY_GROUP_WRITABLE, MU_ERR_PERM_GROUP_WRITABLE,
+    0, _check_gwrfil },
+  { "awrfil", MU_FILE_SAFETY_WORLD_WRITABLE, MU_ERR_PERM_WORLD_WRITABLE,
+    0, _check_awrfil },
+  { "linkwrdir", MU_FILE_SAFETY_LINKED_WRDIR,   MU_ERR_PERM_LINKED_WRDIR,
+    1, _check_linkwrdir },
+  { "gwrdir", MU_FILE_SAFETY_DIR_IWGRP,      MU_ERR_PERM_DIR_IWGRP,
+    1, _check_gwrdir },
+  { "awrdir", MU_FILE_SAFETY_DIR_IWOTH,      MU_ERR_PERM_DIR_IWOTH,
+    1, _check_awrdir },
+  { 0 }
+};
+
+struct file_id
+{
+  dev_t dev;
+  ino_t inode;
+};
+
+static int
+file_id_cmp (const void *item, const void *data)
+{
+  const struct file_id *a = item;
+  const struct file_id *b = data;
+
+  if (a->dev != b->dev)
+    return 1;
+  if (a->inode != b->inode)
+    return 1;
+  return 0;
+}
+
+static int
+file_id_lookup (mu_list_t idlist, dev_t dev, ino_t ino)
+{
+  struct file_id id;
+
+  id.dev = dev;
+  id.inode = ino;
+  return mu_list_locate (idlist, &id, NULL);
+}
+
+static int
+file_id_remember (mu_list_t idlist, dev_t dev, ino_t ino)
+{
+  struct file_id *id = malloc (sizeof (*id));
+  if (!id)
+    {
+      mu_error ("%s", mu_strerror (errno));
+      return 1;
+    }
+  id->dev = dev;
+  id->inode = ino;
+  return mu_list_append (idlist, id);
+}
+
+static struct safety_checker *
+_find_safety_checker (const char *name)
+{
+  struct safety_checker *pck;
+  for (pck = file_safety_check_tab; pck->flag; pck++)
+    if (strcmp (pck->name, name) == 0)
+      return pck;
+  return NULL;
+}
+
+int
+mu_file_safety_name_to_code (const char *name, int *pcode)
+{
+  struct safety_checker *pck = _find_safety_checker (name);
+  if (pck)
+    {
+      *pcode = pck->flag;
+      return 0;
+    }
+  return MU_ERR_NOENT;
+}
+
+int
+mu_file_safety_name_to_error (const char *name, int *pcode)
+{
+  struct safety_checker *pck = _find_safety_checker (name);
+  if (pck)
+    {
+      *pcode = pck->err;
+      return 0;
+    }
+  return MU_ERR_NOENT;
+}
+
+int
+mu_file_safety_check (const char *filename, int mode,
+                     struct mu_auth_data *auth,
+                     mu_list_t idlist)
+{
+  struct file_check_buffer buf;
+  
+  memset (&buf, 0, sizeof (buf));
+  if (stat (filename, &buf.filst) == 0)
+    {
+      struct safety_checker *pck;
+
+      if (idlist)
+       {
+         mu_list_set_destroy_item (idlist, mu_list_free_item);
+         mu_list_set_comparator (idlist, file_id_cmp);
+         if (file_id_lookup (idlist, buf.filst.st_dev, buf.filst.st_ino) == 0)
+           return MU_ERR_EXISTS;
+       }
+
+      if ((mode & MU_FILE_SAFETY_OWNER_MISMATCH) &&
+         auth &&
+         auth->uid != buf.filst.st_uid)
+       return MU_ERR_PERM_OWNER_MISMATCH;
+
+      for (pck = file_safety_check_tab; pck->flag; pck++)
+       if (mode & pck->flag)
+         {
+           if (pck->cdir && !buf.cdir)
+             {
+               char *dirname, *p;
+
+               p = strrchr (filename, '/');
+               if (!p)
+                 dirname = strdup (".");
+               else if (p == filename)
+                 dirname = strdup ("/");
+               else
+                 {
+                   size_t len = p - filename;
+                   dirname = malloc (len + 1);
+                   if (dirname)
+                     {
+                       memcpy (dirname, filename, len);
+                       dirname[len] = 0;
+                     }
+                 }
+               if (!dirname)
+                 return ENOMEM;
+               if (stat (dirname, &buf.dirst))
+                 return errno;
+               buf.cdir = 1;
+             }
+           if (pck->fun (&buf))
+             return pck->err;
+         }
+      if (idlist)
+       file_id_remember (idlist, buf.filst.st_dev, buf.filst.st_ino);
+      return 0;
+    }
+  return errno;
+}
diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors
index 10bad5c..79fed33 100644
--- a/libmailutils/diag/errors
+++ b/libmailutils/diag/errors
@@ -65,7 +65,6 @@ MU_ERR_BADREPLY             _("Invalid reply from the remote 
host")
 MU_ERR_SEQ                  _("Bad command sequence")
 MU_ERR_REPLY                _("Erroneous reply received")
 
-MU_ERR_UNSAFE_PERMS         _("Unsafe file permissions. Set 0600")
 MU_ERR_BAD_AUTH_SCHEME      _("Unsupported authentication scheme")
 MU_ERR_AUTH_FAILURE         _("Authentication failed")
 
@@ -106,3 +105,16 @@ MU_ERR_BADFLAGS                _("Bad value for flags")
 MU_ERR_SOCKTYPE             _("Socket type not supported")
 MU_ERR_FAMILY               _("Address family not supported")
 MU_ERR_SERVICE              _("Requested service not supported")
+
+# File safety check
+MU_ERR_PERM_OWNER_MISMATCH  _("File owner mismatch")
+MU_ERR_PERM_GROUP_WRITABLE  _("Group writable file")
+MU_ERR_PERM_WORLD_WRITABLE  _("World writable file")
+MU_ERR_PERM_GROUP_READABLE  _("Group readable file")
+MU_ERR_PERM_WORLD_READABLE  _("World readable file")
+MU_ERR_PERM_LINKED_WRDIR    _("Linked file in a writable directory")
+MU_ERR_PERM_DIR_IWGRP       _("File in group writable directory")
+MU_ERR_PERM_DIR_IWOTH       _("File in world writable directory")
+
+# A simpler version of the above.  Possibly will be removed in the future.
+MU_ERR_UNSAFE_PERMS         _("Unsafe file permissions")
diff --git a/libmu_auth/tls.c b/libmu_auth/tls.c
index ae3a9a5..d140cb7 100644
--- a/libmu_auth/tls.c
+++ b/libmu_auth/tls.c
@@ -33,8 +33,9 @@
 #include <mailutils/nls.h>
 #include <mailutils/stream.h>
 #include <mailutils/errno.h>
+#include <mailutils/util.h>
 
-struct mu_tls_module_config mu_tls_module_config = { 1, NULL, NULL, NULL };
+struct mu_tls_module_config mu_tls_module_config;
   
 int
 mu_tls_module_init (enum mu_gocs_op op, void *data)
@@ -65,44 +66,38 @@ mu_tls_module_init (enum mu_gocs_op op, void *data)
 static gnutls_dh_params dh_params;
 static gnutls_certificate_server_credentials x509_cred;
 
+/* Return: zero means NOT READY, one means READY */
 int
 mu_check_tls_environment (void)
 {
-  /* Return: zero means NOT READY, one means READY */
-
   if (mu_tls_module_config.ssl_cert && mu_tls_module_config.ssl_key)
     {
-      struct stat st;
-
-      if (stat (mu_tls_module_config.ssl_cert, &st) == -1)
+      int rc = mu_file_safety_check (mu_tls_module_config.ssl_cert,
+                                    
mu_tls_module_config.ssl_cert_safety_checks,
+                                    NULL, NULL);
+      if (rc)
        {
-         mu_error ("%s: %s.", mu_tls_module_config.ssl_cert, 
-                   mu_strerror (errno));
+         mu_error ("%s: %s", mu_tls_module_config.ssl_cert, 
+                   mu_strerror (rc));
          return 0;
        }
-      if (!(st.st_mode & S_IFREG) || !(st.st_mode & S_IFLNK))
+      rc = mu_file_safety_check (mu_tls_module_config.ssl_key,
+                                mu_tls_module_config.ssl_key_safety_checks,
+                                NULL, NULL);
+      if (rc)
        {
-         mu_error (_("%s is not a regular file or a symbolic link."),
-                   mu_tls_module_config.ssl_cert);
+         mu_error ("%s: %s", mu_tls_module_config.ssl_key, 
+                   mu_strerror (rc));
          return 0;
        }
 
-      if (stat (mu_tls_module_config.ssl_key, &st) == -1)
-       {
-         mu_error ("%s: %s.", mu_tls_module_config.ssl_key,
-                   mu_strerror(errno));
-         return 0;
-       }
-      if (!(st.st_mode & S_IFREG) || !(st.st_mode & S_IFLNK))
-       {
-         mu_error (_("%s is not a regular file or a symbolic link."),
-                   mu_tls_module_config.ssl_key);
-         return 0;
-       }
-      if ((st.st_mode & S_IRWXG) || (st.st_mode & S_IRWXO))
+      rc = mu_file_safety_check (mu_tls_module_config.ssl_cafile,
+                                mu_tls_module_config.ssl_cafile_safety_checks,
+                                NULL, NULL);
+      if (rc)
        {
-         mu_error (_("wrong permissions on %s (set 0600)"),
-                   mu_tls_module_config.ssl_key);
+         mu_error ("%s: %s", mu_tls_module_config.ssl_cafile, 
+                   mu_strerror (rc));
          return 0;
        }
     }
diff --git a/libmu_cfg/tls.c b/libmu_cfg/tls.c
index cb5d8d4..d6f44fa 100644
--- a/libmu_cfg/tls.c
+++ b/libmu_cfg/tls.c
@@ -21,8 +21,65 @@
 #include <stdlib.h>
 #include "mailutils/libcfg.h"
 #include <mailutils/tls.h>
+#include <mailutils/util.h>
+#include <mailutils/kwd.h>
 
-static struct mu_tls_module_config tls_settings;
+static struct mu_tls_module_config tls_settings = {
+    1,                   /* enabled by default */
+
+    NULL,                /* Certificate file */
+    MU_FILE_SAFETY_GROUP_WRITABLE |
+     MU_FILE_SAFETY_GROUP_WRITABLE |
+     MU_FILE_SAFETY_LINKED_WRDIR,
+
+    NULL,               /* Key file */ 
+    MU_FILE_SAFETY_ALL, /* Stringent safety checks for keys */
+
+    NULL,               /* CA file */
+    MU_FILE_SAFETY_GROUP_WRITABLE |
+     MU_FILE_SAFETY_GROUP_WRITABLE |
+     MU_FILE_SAFETY_LINKED_WRDIR
+};
+
+
+static int
+cb2_safety_checks (const char *name, void *data)
+{
+  int negate = 0;
+  int val;
+  int *res = data;
+  
+  if (strcmp (name, "none") == 0)
+    {
+      *res = MU_FILE_SAFETY_NONE;
+      return 0;
+    }
+
+  if (*name == '-')
+    {
+      negate = 1;
+      name++;
+    }
+  else if (*name == '+')
+    name++;
+    
+  if (mu_file_safety_name_to_code (name, &val))
+    mu_error (_("unknown keyword: %s"), name);
+  else
+    {
+      if (negate)
+       *res &= ~val;
+      else
+       *res |= val;
+    }
+  return 0;
+}
+
+static int
+cb_safety_checks (void *data, mu_config_value_t *arg)
+{
+  return mu_cfg_string_value_cb (arg, cb2_safety_checks, data);
+}
 
 static struct mu_cfg_param mu_tls_param[] = {
   { "enable", mu_cfg_bool, &tls_settings.enable, 0, NULL,
@@ -36,6 +93,33 @@ static struct mu_cfg_param mu_tls_param[] = {
   { "ssl-cafile", mu_cfg_string, &tls_settings.ssl_cafile, 0, NULL,
     N_("Specify trusted CAs file."),
     N_("file") },
+  { "key-file-safety-checks", mu_cfg_callback,
+    &tls_settings.ssl_key_safety_checks, 0,
+    cb_safety_checks,
+    N_("Configure safety checks for SSL key file.  Argument is a list or "
+       "sequence of check names optionally prefixed with '+' to enable or "
+       "'-' to disable the corresponding check.  Valid check names are:\n"
+       "\n"
+       "  none          disable all checks\n"
+       "  all           enable all checks\n"
+       "  gwrfil        forbid group writable files\n"
+       "  awrfil        forbid world writable files\n"
+       "  grdfil        forbid group readable files\n"
+       "  ardfil        forbid world writable files\n"
+       "  linkwrdir     forbid symbolic links in group or world writable 
directories\n"
+       "  gwrdir        forbid files in group writable directories\n"
+       "  awrdir        forbid files in world writable directories\n"),
+    N_("arg: list") },  
+  { "cert-file-safety-checks", mu_cfg_callback,
+    &tls_settings.ssl_cert_safety_checks, 0,
+    cb_safety_checks,
+    N_("Configure safety checks for SSL certificate.  See above for a 
description of <arg>."),
+    N_("arg: list") },  
+  { "ca-file-safety-checks", mu_cfg_callback,
+    &tls_settings.ssl_cafile_safety_checks, 0,
+    cb_safety_checks,
+    N_("Configure safety checks for SSL certificate authority file.  See above 
for a description of <arg>."),
+    N_("arg: list") },  
   { NULL }
 }; 
 
diff --git a/maidag/forward.c b/maidag/forward.c
index 7846485..dd02164 100644
--- a/maidag/forward.c
+++ b/maidag/forward.c
@@ -19,154 +19,6 @@
 
 #include "maidag.h"
 
-/* Functions for checking file mode of .forward and its directory.
-   Each of these checks certain bits and returns 0 if they are OK
-   and non-0 otherwise. */
-
-static int
-check_iwgrp (struct stat *filest, struct stat *dirst)
-{
-  return filest->st_mode & S_IWGRP;
-}
-
-static int
-check_iwoth (struct stat *filest, struct stat *dirst)
-{
-  return filest->st_mode & S_IWOTH;
-}
-
-static int
-check_linked_wrdir (struct stat *filest, struct stat *dirst)
-{
-  return (filest->st_mode & S_IFLNK) && (dirst->st_mode & (S_IWGRP | S_IWOTH));
-}
-
-static int
-check_dir_iwgrp (struct stat *filest, struct stat *dirst)
-{
-  return dirst->st_mode & S_IWGRP;
-}
-
-static int
-check_dir_iwoth (struct stat *filest, struct stat *dirst)
-{
-  return dirst->st_mode & S_IWOTH;
-}
-
-/* The table of permission checkers below has this type: */
-struct perm_checker
-{
-  int flag;              /* FWD_ flag that enables this entry */
-  char *descr;           /* Textual description to use if FUN returns !0 */
-  int (*fun) (struct stat *filest, struct stat *dirst); /* Checker function */
-};
-
-static struct perm_checker perm_check_tab[] = {
-  { FWD_IWGRP, N_("group writable forward file"), check_iwgrp },
-  { FWD_IWOTH, N_("world writable forward file"), check_iwoth },
-  { FWD_LINK, N_("linked forward file in writable dir"), check_linked_wrdir },
-  { FWD_DIR_IWGRP, N_("forward file in group writable directory"),
-    check_dir_iwgrp },
-  { FWD_DIR_IWOTH, N_("forward file in world writable directory"),
-    check_dir_iwoth },
-  { 0 }
-};
-
-static mu_list_t idlist;
-
-struct file_id
-{
-  dev_t dev;
-  ino_t inode;
-};
-
-static int
-file_id_cmp (const void *item, const void *data)
-{
-  const struct file_id *a = item;
-  const struct file_id *b = data;
-
-  if (a->dev != b->dev)
-    return 1;
-  if (a->inode != b->inode)
-    return 1;
-  return 0;
-}
-
-static int
-file_id_lookup (dev_t dev, ino_t ino)
-{
-  struct file_id id;
-
-  id.dev = dev;
-  id.inode = ino;
-  return mu_list_locate (idlist, &id, NULL);
-}
-
-static int
-file_id_remember (dev_t dev, ino_t ino)
-{
-  struct file_id *id = malloc (sizeof (*id));
-  if (!id)
-    {
-      mu_error ("%s", mu_strerror (errno));
-      return 1;
-    }
-  id->dev = dev;
-  id->inode = ino;
-  return mu_list_append (idlist, id);
-}
-
-
-/* Check if the forwrd file FILENAME has right permissions and file mode.
-   DIRST describes the directory holding the file, AUTH gives current user
-   authority. */
-int
-check_forward_permissions (const char *filename, struct stat *dirst,
-                          struct mu_auth_data *auth)
-{
-  struct stat st;
-  
-  if (stat (filename, &st) == 0)
-    {
-      int i;
-
-      if (!idlist)
-       {
-         mu_list_create (&idlist);
-         mu_list_set_comparator (idlist, file_id_cmp);
-       }
-      else if (file_id_lookup (st.st_dev, st.st_ino) == 0)
-       {
-         mu_diag_output (MU_DIAG_NOTICE,
-                         _("skipping forward file %s: already processed"),
-                         filename);
-         return 1;
-       }
-      
-      if ((forward_file_checks & FWD_OWNER) &&
-         auth->uid != st.st_uid)
-       {
-         mu_error (_("%s not owned by %s"), filename, auth->name);
-         return 1;
-       }
-      for (i = 0; perm_check_tab[i].flag; i++)
-       if ((forward_file_checks & perm_check_tab[i].flag)
-           && perm_check_tab[i].fun (&st, dirst))
-         {
-           mu_error ("%s: %s", filename, gettext (perm_check_tab[i].descr));
-           return 1;
-         }
-      file_id_remember (st.st_dev, st.st_ino);
-      return 0;
-    }
-  else if (errno != ENOENT)
-    mu_error (_("%s: cannot stat file: %s"),
-             filename, mu_strerror (errno));
-  return 1;
-}
-
-
 /* Auxiliary functions */
 
 /* Forward message MSG to given EMAIL, using MAILER and sender address FROM */
@@ -320,6 +172,9 @@ process_forward (mu_message_t msg, char *filename, const 
char *myname)
   return result;
 }
 
+
+static mu_list_t idlist;
+
 /* Check if the forward file FWFILE for user given by AUTH exists, and if
    so, use to to forward message MSG. */
 enum maidag_forward_result
@@ -328,7 +183,8 @@ maidag_forward (mu_message_t msg, struct mu_auth_data 
*auth, char *fwfile)
   struct stat st;
   char *filename;
   enum maidag_forward_result result = maidag_forward_none;
-
+  int rc;
+  
   if (fwfile[0] != '/')
     {
       if (stat (auth->dir, &st))
@@ -353,8 +209,20 @@ maidag_forward (mu_message_t msg, struct mu_auth_data 
*auth, char *fwfile)
       return maidag_forward_error;
     }
 
-  if (check_forward_permissions (filename, &st, auth) == 0)
+  if (!idlist)
+    mu_list_create (&idlist);
+
+  rc = mu_file_safety_check (filename, forward_file_checks,
+                                 auth, idlist);
+  if (rc == 0)
     result = process_forward (msg, filename, auth->name);
+  else if (rc)
+    mu_diag_output (MU_DIAG_NOTICE,
+                   _("skipping forward file %s: already processed"),
+                   filename);
+  else
+    mu_error (_("ignoring forward file %s: %s"),
+             filename, mu_strerror (rc));
   
   free (filename);
   return result;
diff --git a/maidag/maidag.c b/maidag/maidag.c
index 9ea7c18..a9fe7ac 100644
--- a/maidag/maidag.c
+++ b/maidag/maidag.c
@@ -36,7 +36,14 @@ maidag_script_fun script_handler;
 mu_list_t script_list;
 
 char *forward_file = NULL;
-int forward_file_checks = FWD_ALL;
+#define FORWARD_FILE_PERM_CHECK (                                      \
+                          MU_FILE_SAFETY_OWNER_MISMATCH |      \
+                          MU_FILE_SAFETY_GROUP_WRITABLE |      \
+                          MU_FILE_SAFETY_WORLD_WRITABLE |      \
+                          MU_FILE_SAFETY_LINKED_WRDIR |                \
+                          MU_FILE_SAFETY_DIR_IWGRP |           \
+                          MU_FILE_SAFETY_DIR_IWOTH )
+int forward_file_checks = FORWARD_FILE_PERM_CHECK;
 
 /* Debuggig options */
 int debug_level;           /* General debugging level */ 
@@ -326,44 +333,32 @@ cb_group (void *data, mu_config_value_t *arg)
   return mu_cfg_string_value_cb (arg, cb2_group, *plist);
 }
 
-static struct mu_kwd forward_checks[] = {
-  { "all", FWD_ALL },
-  { "owner", FWD_OWNER },
-  { "groupwritablefile", FWD_IWGRP },
-  { "file_iwgrp", FWD_IWGRP },
-  { "worldwritablefile", FWD_IWOTH },
-  { "file_iwoth", FWD_IWOTH },
-  { "linkedfileinwritabledir", FWD_LINK },
-  { "link", FWD_LINK },
-  { "fileingroupwritabledir", FWD_DIR_IWGRP },
-  { "dir_iwgrp", FWD_DIR_IWGRP },
-  { "fileinworldwritabledir", FWD_DIR_IWOTH },
-  { "dir_iwoth", FWD_DIR_IWOTH },
-  { NULL }
-};
-
 static int
 cb2_forward_file_checks (const char *name, void *data)
 {
-  int negate = 0;
-  const char *str;
   int val;
-
+  int negate = 0;
+  
+  if (strcmp (name, "all") == 0)
+    {
+      forward_file_checks = FORWARD_FILE_PERM_CHECK;
+      return 0;
+    }
   if (strcmp (name, "none") == 0)
     {
       forward_file_checks = 0;
       return 0;
     }
   
-  if (strlen (name) > 2 && mu_c_strncasecmp (name, "no", 2) == 0)
+  if (*name == '-')
     {
       negate = 1;
-      str = name + 2;
+      name++;
     }
-  else
-    str = name;
+  else if (*name == '+')
+    name++;
 
-  if (mu_kwd_xlat_name_ci (forward_checks, str, &val))
+  if (mu_file_safety_name_to_code (name, &val))
     mu_error (_("unknown keyword: %s"), name);
   else
     {
diff --git a/maidag/maidag.h b/maidag/maidag.h
index 75bafc2..2be3818 100644
--- a/maidag/maidag.h
+++ b/maidag/maidag.h
@@ -109,15 +109,6 @@ extern int debug_level;
 #define MAXFD 64
 #define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE)
 
-/* .forward file checks */
-#define FWD_OWNER     0x0001 /* file ownership */
-#define FWD_IWGRP     0x0002 /* group writable forward file */
-#define FWD_IWOTH     0x0004 /* world writable forward file */
-#define FWD_LINK      0x0008 /* linked forward file in writable dir */
-#define FWD_DIR_IWGRP 0x0010 /* forward file in group writable directory */
-#define FWD_DIR_IWOTH 0x0020 /* forward file in world writable directory */
-#define FWD_ALL 
(FWD_OWNER|FWD_IWGRP|FWD_IWOTH|FWD_LINK|FWD_DIR_IWOTH|FWD_DIR_IWGRP)
-
 enum maidag_mode
   {
     mode_mda,


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]