diff options
-rw-r--r-- | comsat/Makefile.am | 2 | ||||
-rw-r--r-- | comsat/comsat.c | 165 | ||||
-rw-r--r-- | libmailutils/cli/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/cli/acl.c | 267 |
4 files changed, 344 insertions, 91 deletions
diff --git a/comsat/Makefile.am b/comsat/Makefile.am index e67b21848..a661ffe11 100644 --- a/comsat/Makefile.am +++ b/comsat/Makefile.am @@ -31,7 +31,7 @@ biff.rc.h: $(top_srcdir)/comsat/biff.rc $(top_srcdir)/comsat/biff.rc > biff.rc.h comsatd_LDADD = \ - ${MU_APP_LIBRARIES}\ + ${MU_APP_NEW_LIBRARIES}\ ${MU_LIB_MBOX}\ ${MU_LIB_IMAP}\ ${MU_LIB_POP}\ diff --git a/comsat/comsat.c b/comsat/comsat.c index 0911a3729..c12ed2082 100644 --- a/comsat/comsat.c +++ b/comsat/comsat.c @@ -18,7 +18,7 @@ #include "comsat.h" #define MU_CFG_COMPATIBILITY /* This source uses deprecated cfg interfaces */ #include "mailutils/libcfg.h" -#include "mailutils/libargp.h" +#include "mailutils/cli.h" #ifndef PATH_DEV # define PATH_DEV "/dev" @@ -59,44 +59,62 @@ typedef struct utmp UTMP; #define MAX_TTY_SIZE (sizeof (PATH_TTY_PFX) + sizeof (((UTMP*)0)->ut_line)) const char *program_version = "comsatd (" PACKAGE_STRING ")"; -static char doc[] = N_("GNU comsatd -- notify users about incoming mail"); -static char args_doc[] = N_("\n--test MBOX-URL MSG-QID"); -#define OPT_FOREGROUND 256 +int test_mode; +char *biffrc = BIFF_RC; +mu_m_server_t server; -static struct argp_option options[] = +static void +set_inetd_mode (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) { - { "test", 't', NULL, 0, N_("run in test mode"), 0 }, - { "foreground", OPT_FOREGROUND, 0, 0, N_("remain in foreground"), 0}, - { "inetd", 'i', 0, 0, N_("run in inetd mode"), 0 }, - { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL, - N_("runs in daemon mode with a maximum of NUMBER children"), 0 }, - { "file", 'f', N_("FILE"), 0, - N_("read FILE instead of .biffrc"), 0 }, - { NULL, 0, NULL, 0, NULL, 0 } -}; - -static error_t comsatd_parse_opt (int key, char *arg, - struct argp_state *state); + mu_m_server_set_mode (server, MODE_INTERACTIVE); +} + +static void +set_daemon_mode (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + mu_m_server_set_mode (server, MODE_DAEMON); + if (arg) + { + size_t max_children; + char *errmsg; + int rc = mu_str_to_c (arg, mu_c_size, &max_children, &errmsg); + if (rc) + { + mu_parseopt_error (po, _("%s: bad argument"), arg); + exit (po->po_exit_error); + } + mu_m_server_set_max_children (server, max_children); + } +} -static struct argp argp = { - options, - comsatd_parse_opt, - args_doc, - doc, - NULL, - NULL, NULL -}; +static void +set_foreground (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + mu_m_server_set_foreground (server, 1); +} -static const char *comsat_argp_capa[] = { - "mailutils", - "common", - "debug", - "logging", - "mailbox", - "locking", - NULL -}; +static struct mu_option comsat_options[] = { + { "test", 't', NULL, MU_OPTION_DEFAULT, + N_("run in test mode"), + mu_c_bool, &test_mode }, + { "foreground", 0, NULL, MU_OPTION_DEFAULT, + N_("remain in foreground"), + mu_c_bool, NULL, set_foreground }, + { "inetd", 'i', NULL, MU_OPTION_DEFAULT, + N_("run in inetd mode"), + mu_c_bool, NULL, set_inetd_mode }, + { "daemon", 'd', N_("NUMBER"), MU_OPTION_ARG_OPTIONAL, + N_("runs in daemon mode with a maximum of NUMBER children"), + mu_c_string, NULL, set_daemon_mode }, + { "file", 'f', N_("FILE"), MU_OPTION_DEFAULT, + N_("read FILE instead of .biffrc"), + mu_c_string, &biffrc }, + MU_OPTION_END +}, *options[] = { comsat_options, NULL }; #define SUCCESS 0 #define NOT_HERE 1 @@ -107,7 +125,6 @@ char *hostname; const char *username; int require_tty; int biffrc_errors = BIFFRC_ERRORS_TO_TTY | BIFFRC_ERRORS_TO_ERR; -mu_m_server_t server; static void comsat_init (void); static int comsat_main (int fd); @@ -118,9 +135,6 @@ static char *mailbox_path (const char *user); static int change_user (const char *user); static int reload = 0; -int test_mode; -char *biffrc = BIFF_RC; - static int biffrc_error_ctl (mu_config_value_t *val, int flag) { @@ -171,55 +185,30 @@ struct mu_cfg_param comsat_cfg_param[] = { 0, NULL, N_("Set overflow control interval.") }, { "overflow-delay-time", mu_c_time, &overflow_delay_time, - 0, NULL, + 0, NULL, N_("Time to sleep after the first overflow occurs.") }, { ".server", mu_cfg_section, NULL, 0, NULL, N_("Server configuration.") }, { NULL } }; -static error_t -comsatd_parse_opt (int key, char *arg, struct argp_state *state) -{ - static mu_list_t lst; - - switch (key) - { - case 'd': - mu_argp_node_list_new (lst, "mode", "daemon"); - if (arg) - mu_argp_node_list_new (lst, "max-children", arg); - break; - - case 'f': - biffrc = arg; - break; - - case 'i': - mu_argp_node_list_new (lst, "mode", "inetd"); - break; +static char const *alt_args[] = { N_("--test MBOX-URL MSG-QID"), NULL }; - case OPT_FOREGROUND: - mu_argp_node_list_new (lst, "foreground", "yes"); - break; - - case 't': - test_mode = 1; - break; - - case ARGP_KEY_INIT: - mu_argp_node_list_init (&lst); - break; - - case ARGP_KEY_FINI: - mu_argp_node_list_finish (lst, NULL, NULL); - break; +static struct mu_cli_setup cli = { + options, + comsat_cfg_param, + N_("GNU comsatd -- notify users about incoming mail"), + "", + alt_args, +}; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} +static char *capa[] = { + "debug", + "logging", + "mailbox", + "locking", + NULL +}; static RETSIGTYPE sig_hup (int sig) @@ -558,12 +547,11 @@ int main (int argc, char **argv) { int c; - int ind; - + char **save_argv; + /* Native Language Support */ MU_APP_INIT_NLS (); - mu_argp_init (NULL, NULL); comsat_init (); mu_acl_cfg_init (); mu_m_server_create (&server, program_version); @@ -578,19 +566,16 @@ main (int argc, char **argv) /* FIXME: timeout is not needed. How to disable it? */ mu_log_syslog = 1; + + save_argv = argv; - if (mu_app_init (&argp, comsat_argp_capa, comsat_cfg_param, argc, argv, 0, - &ind, server)) - exit (EXIT_FAILURE); + mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); if (test_mode) { struct passwd *pw; char *user; - argc -= ind; - argv += ind; - mu_stdstream_strerr_setup (MU_STRERR_STDERR); biffrc_errors = BIFFRC_ERRORS_TO_ERR; if (argc < 2 || argc > 2) @@ -630,7 +615,7 @@ main (int argc, char **argv) if (mu_m_server_mode (server) == MODE_DAEMON) { - if (argv[0][0] != '/') + if (save_argv[0][0] != '/') mu_diag_output (MU_DIAG_NOTICE, _("program name is not absolute; reloading will not " "be possible")); @@ -651,7 +636,7 @@ main (int argc, char **argv) if (reload) { mu_diag_output (MU_DIAG_NOTICE, _("restarting")); - execvp (argv[0], argv); + execvp (save_argv[0], save_argv); } } else diff --git a/libmailutils/cli/Makefile.am b/libmailutils/cli/Makefile.am index 48770e844..e506b9105 100644 --- a/libmailutils/cli/Makefile.am +++ b/libmailutils/cli/Makefile.am @@ -18,6 +18,7 @@ noinst_LTLIBRARIES = libcli.la libcli_la_SOURCES = \ + acl.c\ capa.c\ cli.c\ stdcapa.c diff --git a/libmailutils/cli/acl.c b/libmailutils/cli/acl.c new file mode 100644 index 000000000..778c3f52c --- /dev/null +++ b/libmailutils/cli/acl.c @@ -0,0 +1,267 @@ +/* This file is part of GNU Mailutils + Copyright (C) 2007-2012, 2014-2016 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or (at + your option) any later version. + + GNU Mailutils 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "mailutils/acl.h" +#include "mailutils/argcv.h" +#include "mailutils/cidr.h" +#include "mailutils/cfg.h" +#include "mailutils/errno.h" +#include "mailutils/nls.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#define ISSPACE(c) ((c)==' '||(c)=='\t') + +#define SKIPWS(p) while (*(p) && ISSPACE (*(p))) (p)++; + +static const char * +getword (mu_config_value_t *val, int *pn) +{ + int n = (*pn)++; + mu_config_value_t *v; + + if (n >= val->v.arg.c) + { + mu_error (_("not enough arguments")); + return NULL; + } + v = &val->v.arg.v[n]; + if (mu_cfg_assert_value_type (v, MU_CFG_STRING)) + return NULL; + return v->v.string; +} + +static int +parsearg (mu_config_value_t *val, struct mu_cidr *cidr, char **prest) +{ + const char *w; + int n = 0; + int rc; + + if (mu_cfg_assert_value_type (val, MU_CFG_ARRAY)) + return 1; + + w = getword (val, &n); + if (!w) + return 1; + if (strcmp (w, "from") == 0) { + w = getword (val, &n); + if (!w) + return 1; + } + + if (strcmp (w, "any") == 0) + cidr->len = 0; + else + { + rc = mu_cidr_from_string (cidr, w); + if (rc) + { + mu_error (_("invalid source CIDR: %s"), mu_strerror (rc)); + return 1; + } + } + + if (prest) + { + if (n == val->v.arg.c) + *prest = NULL; + else + { + size_t size = 0; + int i; + char *buf; + + for (i = n; i < val->v.arg.c; i++) + { + if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING)) + return 1; + size += strlen (val->v.arg.v[i].v.string) + 1; + } + + buf = malloc (size); + if (!buf) + { + mu_error ("%s", mu_strerror (errno)); + return 1; + } + + *prest = buf; + for (i = n; i < val->v.arg.c; i++) + { + if (i > n) + *buf++ = ' '; + strcpy (buf, val->v.arg.v[i].v.string); + buf += strlen (buf); + } + *buf = 0; + } + } + else if (n != val->v.arg.c) + { + mu_error (_("junk after IP address")); + return 1; + } + return 0; +} + +static int +cb_allow (void *data, mu_config_value_t *val) +{ + int rc; + mu_acl_t acl = *(mu_acl_t*)data; + struct mu_cidr cidr; + + if (parsearg (val, &cidr, NULL)) + return 1; + rc = mu_acl_append (acl, mu_acl_accept, NULL, &cidr); + if (rc) + mu_error (_("cannot append acl entry: %s"), mu_strerror (rc)); + return rc; +} + +static int +cb_deny (void *data, mu_config_value_t *val) +{ + int rc; + mu_acl_t acl = *(mu_acl_t*)data; + struct mu_cidr cidr; + + if (parsearg (val, &cidr, NULL)) + return 1; + rc = mu_acl_append (acl, mu_acl_deny, NULL, &cidr); + if (rc) + mu_error (_("cannot append acl entry: %s"), mu_strerror (rc)); + return rc; +} + +static int +cb_log (void *data, mu_config_value_t *val) +{ + int rc; + mu_acl_t acl = *(mu_acl_t*)data; + struct mu_cidr cidr; + char *rest; + + if (parsearg (val, &cidr, &rest)) + return 1; + rc = mu_acl_append (acl, mu_acl_log, rest, &cidr); + if (rc) + mu_error (_("cannot append acl entry: %s"), mu_strerror (rc)); + return rc; +} + +static int +cb_exec (void *data, mu_config_value_t *val) +{ + int rc; + mu_acl_t acl = *(mu_acl_t*)data; + struct mu_cidr cidr; + char *rest; + + if (parsearg (val, &cidr, &rest)) + return 1; + rc = mu_acl_append (acl, mu_acl_exec, rest, &cidr); + if (rc) + mu_error (_("cannot append acl entry: %s"), mu_strerror (rc)); + return rc; +} + +static int +cb_ifexec (void *data, mu_config_value_t *val) +{ + int rc; + mu_acl_t acl = *(mu_acl_t*)data; + struct mu_cidr cidr; + char *rest; + + if (parsearg (val, &cidr, &rest)) + return 1; + rc = mu_acl_append (acl, mu_acl_ifexec, rest, &cidr); + if (rc) + mu_error (_("cannot append acl entry: %s"), mu_strerror (rc)); + return rc; +} + +static struct mu_cfg_param acl_param[] = { + { "allow", mu_cfg_callback, NULL, 0, cb_allow, + N_("Allow connections from this IP address. Optional word `from' is " + "allowed between it and its argument. The same holds true for other " + "actions below."), + N_("addr: IP") }, + { "deny", mu_cfg_callback, NULL, 0, cb_deny, + N_("Deny connections from this IP address."), + N_("addr: IP") }, + { "log", mu_cfg_callback, NULL, 0, cb_log, + N_("Log connections from this IP address."), + N_("addr: IP") }, + { "exec", mu_cfg_callback, NULL, 0, cb_exec, + N_("Execute supplied program if a connection from this IP address is " + "requested. Arguments are:\n" + " <addr: IP> <program: string>\n" + "Following macros are expanded in <program> before executing:\n" + " address - Source IP address\n" + " port - Source port number\n") }, + { "ifexec", mu_cfg_callback, NULL, 0, cb_ifexec, + N_("If a connection from this IP address is requested, execute supplied " + "program and allow or deny the connection depending on its exit code. " + "See `exec' for a description of its arguments.") }, + { NULL } +}; + +static int +acl_section_parser (enum mu_cfg_section_stage stage, + const mu_cfg_node_t *node, + const char *section_label, void **section_data, + void *call_data, + mu_cfg_tree_t *tree) +{ + switch (stage) + { + case mu_cfg_section_start: + { + void *data = *section_data; + mu_acl_create ((mu_acl_t*)data); + } + break; + + case mu_cfg_section_end: + break; + } + return 0; +} + +void +mu_acl_cfg_init (void) +{ + struct mu_cfg_section *section; + if (mu_create_canned_section ("acl", §ion) == 0) + { + section->parser = acl_section_parser; + mu_cfg_section_add_params (section, acl_param); + } +} |