Commit dfed0be6 dfed0be6c0fb0541234422af700e955b77d09bd4 by Sergey Poznyakoff

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.
1 parent 502c6353
......@@ -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 *);
......
......@@ -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
......
......@@ -24,6 +24,7 @@ libbase_la_SOURCES = \
argcvjoin.c\
argcvrem.c\
assoc.c\
filesafety.c\
daemon.c\
date.c\
fdwait.c\
......
/* 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;
}
......@@ -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")
......
......@@ -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;
}
}
......
......@@ -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 }
};
......
......@@ -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;
......
......@@ -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
{
......
......@@ -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,
......