Commit 643be57e 643be57eb09fe6485ccc8f4cf3ac9a592c207bb5 by Sergey Poznyakoff

* comsat/Makefile.am: Remove cfg.c

* comsat/cfg.c: Remove.
* comsat/comsat.c: Use MU configuration and acls.
* comsat/comsat.h: Include acl.h
* libproto/maildir/mbox.c (maildir_qfetch): Bugfix.
1 parent b7e41daa
2007-12-30 Sergey Poznyakoff <gray@gnu.org.ua>
* comsat/Makefile.am: Remove cfg.c
* comsat/cfg.c: Remove.
* comsat/comsat.c: Use MU configuration and acls.
* comsat/comsat.h: Include acl.h
* libproto/maildir/mbox.c (maildir_qfetch): Bugfix.
* NEWS: Update.
* frm/testsuite/frm/test.exp: Call mu_init with -noflags option.
......
......@@ -21,7 +21,7 @@ INCLUDES = @MU_COMMON_INCLUDES@
sbin_PROGRAMS = comsatd
comsatd_SOURCES = action.c cfg.c comsat.c comsat.h
comsatd_SOURCES = action.c comsat.c comsat.h
comsatd_LDADD = \
${MU_APP_LIBRARIES}\
......
/* This file is part of GNU Mailutils.
Copyright (C) 1998, 2001, 2002, 2005, 2007 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 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; see the file COPYING. If not, write
to the Free Software Foundation, Inc., 51 Franklin Street,
Fifth Floor, Boston, MA 02110-1301 USA. */
#include "comsat.h"
typedef struct netdef netdef_t;
struct netdef
{
netdef_t *next;
unsigned int ipaddr;
unsigned int netmask;
};
#define ACT_ALLOW 0
#define ACT_DENY 1
typedef struct acl acl_t;
struct acl
{
acl_t *next;
netdef_t *netlist;
int action;
};
acl_t *acl_head, *acl_tail;
#define DOTTED_QUAD_LEN 16
static int
read_address (char **line_ptr, char *ptr)
{
char *startp = *line_ptr;
char *endp;
int dotcount = 0;
for (endp = startp; *endp; endp++, ptr++)
if (!(isdigit (*endp) || *endp == '.'))
break;
else if (endp < startp + DOTTED_QUAD_LEN)
{
if (*endp == '.')
dotcount++;
*ptr = *endp;
}
else
break;
*line_ptr = endp;
*ptr = 0;
return dotcount;
}
static netdef_t *
netdef_parse (char *str)
{
unsigned int ipaddr, netmask;
netdef_t *netdef;
char ipbuf[DOTTED_QUAD_LEN+1];
if (strcmp (str, "any") == 0)
{
ipaddr = 0;
netmask = 0;
}
else
{
read_address (&str, ipbuf);
ipaddr = inet_addr (ipbuf);
if (ipaddr == INADDR_NONE)
return NULL;
if (*str == 0)
netmask = 0xfffffffful;
else if (*str != '/')
return NULL;
else
{
str++;
if (read_address (&str, ipbuf) == 0)
{
/* netmask length */
unsigned int len = strtoul (ipbuf, NULL, 0);
if (len > 32)
return NULL;
netmask = 0xfffffffful >> (32-len);
netmask <<= (32-len);
}
else
netmask = inet_network (ipbuf);
netmask = htonl (netmask);
}
}
netdef = malloc (sizeof *netdef);
if (!netdef)
{
mu_error (_("Out of memory"));
exit (1);
}
netdef->next = NULL;
netdef->ipaddr = ipaddr;
netdef->netmask = netmask;
return netdef;
}
void
read_config (const char *config_file)
{
FILE *fp;
int line;
char buf[128];
char *ptr;
if (!config_file)
return;
fp = fopen (config_file, "r");
if (!fp)
{
mu_error (_("Cannot open config file %s: %s"), config_file,
mu_strerror (errno));
return;
}
line = 0;
while ((ptr = fgets (buf, sizeof buf, fp)))
{
int len, i;
int argc;
char **argv;
int action;
netdef_t *head, *tail;
acl_t *acl;
line++;
len = strlen (ptr);
if (len > 0 && ptr[len-1] == '\n')
ptr[--len] = 0;
while (*ptr && isspace (*ptr))
ptr++;
if (!*ptr || *ptr == '#')
continue;
mu_argcv_get (ptr, "", NULL, &argc, &argv);
if (argc < 2)
{
mu_error (_("%s:%d: too few fields"), config_file, line);
mu_argcv_free (argc, argv);
continue;
}
if (strcmp (argv[0], "allow-biffrc") == 0)
{
if (strcmp (argv[1], "yes") == 0)
allow_biffrc = 1;
else if (strcmp (argv[1], "no") == 0)
allow_biffrc = 0;
else
mu_error (_("%s:%d: yes or no expected"), config_file, line);
}
else if (strcmp (argv[0], "max-requests") == 0)
maxrequests = strtoul (argv[1], NULL, 0);
else if (strcmp (argv[0], "request-control-interval") == 0)
request_control_interval = strtoul (argv[1], NULL, 0);
else if (strcmp (argv[0], "overflow-control-interval") == 0)
overflow_control_interval = strtoul (argv[1], NULL, 0);
else if (strcmp (argv[0], "overflow-delay-time") == 0)
overflow_delay_time = strtoul (argv[1], NULL, 0);
else if (strcmp (argv[0], "max-lines") == 0)
maxlines = strtoul (argv[1], NULL, 0);
else if (strcmp (argv[0], "acl") == 0)
{
if (strcmp (argv[1], "allow") == 0)
action = ACT_ALLOW;
else if (strcmp (argv[1], "deny") == 0)
action = ACT_DENY;
else
{
mu_error (_("%s:%d: unknown keyword"), config_file, line);
mu_argcv_free (argc, argv);
continue;
}
head = tail = NULL;
for (i = 2; i < argc; i++)
{
netdef_t *cur = netdef_parse (argv[i]);
if (!cur)
{
mu_error (_("%s:%d: cannot parse netdef: %s"),
config_file, line, argv[i]);
continue;
}
if (!tail)
head = cur;
else
tail->next = cur;
tail = cur;
}
mu_argcv_free (argc, argv);
acl = malloc (sizeof *acl);
if (!acl)
{
mu_error (_("Out of memory"));
exit (1);
}
acl->next = NULL;
acl->action = action;
acl->netlist = head;
if (!acl_tail)
acl_head = acl;
else
acl_tail->next = acl;
acl_tail = acl;
}
}
fclose (fp);
}
/*NOTE: currently unused. */
#if 0
static void
netdef_free (netdef_t *netdef)
{
netdef_t *next;
while (netdef)
{
next = netdef->next;
free (netdef);
netdef = next;
}
}
static void
acl_free (acl_t *acl)
{
acl_t *next;
while (acl)
{
next = acl->next;
netdef_free (acl->netlist);
free (acl);
acl = next;
}
}
static void
discard_acl (acl_t *mark)
{
if (mark)
{
acl_free (mark->next);
acl_tail = mark;
acl_tail->next = NULL;
}
else
acl_head = acl_tail = NULL;
}
#endif
int
acl_match (struct sockaddr_in *sa_in)
{
acl_t *acl;
unsigned int ip;
ip = sa_in->sin_addr.s_addr;
for (acl = acl_head; acl; acl = acl->next)
{
netdef_t *net;
for (net = acl->netlist; net; net = net->next)
{
if (net->ipaddr == (ip & net->netmask))
return acl->action;
}
}
return ACT_ALLOW;
}
......@@ -103,6 +103,7 @@ struct mu_gocs_daemon default_gocs_daemon = {
int maxlines = 5;
char hostname[MAXHOSTNAMELEN];
const char *username;
mu_acl_t comsat_acl;
static void comsat_init (void);
static void comsat_daemon_init (void);
......@@ -116,7 +117,6 @@ static void change_user (const char *user);
static int xargc;
static char **xargv;
char *config_file = NULL;
int test_mode;
static error_t
......@@ -125,7 +125,7 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'c':
config_file = arg;
/* FIXME: convert config to the new format and parse it */
break;
case 't':
......@@ -138,20 +138,43 @@ comsatd_parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
struct mu_cfg_param comsat_cfg_param[] = {
{ "allow-biffrc", mu_cfg_bool, &allow_biffrc, 0, NULL,
N_("Read .biffrc file from the user home directory") },
{ "max-lines", mu_cfg_int, &maxlines, 0, NULL,
N_("Maximum number of message body lines to be output.") },
{ "max-requests", mu_cfg_uint, &maxrequests, 0, NULL,
N_("Maximum number of incoming requests per `request-control-interval' "
"seconds.") },
{ "request-control-interval", mu_cfg_time, &request_control_interval,
0, NULL,
N_("Set control interval.") },
{ "overflow-control-interval", mu_cfg_time, &overflow_control_interval,
0, NULL,
N_("Set overflow control interval.") },
{ "overflow-delay-time", mu_cfg_time, &overflow_delay_time,
0, NULL,
N_("Time to sleep after the first overflow occurs.") },
{ "acl", mu_cfg_section, },
{ NULL }
};
int
main (int argc, char **argv)
{
int c;
int ind;
/* Native Language Support */
mu_init_nls ();
mu_argp_init (program_version, NULL);
mu_gocs_daemon = default_gocs_daemon;
comsat_init ();
mu_acl_cfg_init ();
if (mu_app_init (&argp, comsat_argp_capa, NULL, argc, argv, 0, &ind, NULL))
if (mu_app_init (&argp, comsat_argp_capa, comsat_cfg_param, argc, argv, 0,
&ind, &comsat_acl))
exit (1);
argc -= ind;
......@@ -161,11 +184,6 @@ main (int argc, char **argv)
{
char *user;
comsat_init ();
if (config_file)
read_config (config_file);
if (argc == 0)
exit (0);
if (argc < 2 || argc > 2)
{
mu_error (_("Mailbox URL and message QID are required in test mode"));
......@@ -198,8 +216,6 @@ main (int argc, char **argv)
exit (EXIT_FAILURE);
}
comsat_init ();
if (mu_gocs_daemon.mode == MODE_DAEMON)
{
/* Preserve invocation arguments */
......@@ -218,9 +234,6 @@ main (int argc, char **argv)
mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
}
if (config_file)
read_config (config_file);
chdir ("/");
if (mu_gocs_daemon.mode == MODE_DAEMON)
......@@ -370,11 +383,58 @@ comsat_daemon (int port)
}
int
check_connection (int fd, struct sockaddr *addr, socklen_t addrlen)
{
switch (addr->sa_family)
{
case PF_UNIX:
mu_diag_output (MU_DIAG_INFO, _("connect from socket"));
break;
case PF_INET:
{
struct sockaddr_in *s_in = (struct sockaddr_in *)addr;
if (comsat_acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (comsat_acl, addr, addrlen,
&res);
if (rc)
{
mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
inet_ntoa (s_in->sin_addr), mu_strerror (rc));
return 1;
}
switch (res)
{
case mu_acl_result_undefined:
mu_diag_output (MU_DIAG_INFO,
_("%s: undefined ACL result; access allowed"),
inet_ntoa (s_in->sin_addr));
break;
case mu_acl_result_accept:
break;
case mu_acl_result_deny:
mu_error (_("Access from %s blocked."),
inet_ntoa (s_in->sin_addr));
return 1;
}
}
}
}
return 0;
}
int
comsat_main (int fd)
{
int rdlen;
int len;
struct sockaddr_in sin_from;
struct sockaddr fromaddr;
char buffer[216]; /*FIXME: Arbitrary size */
pid_t pid;
char tty[MAX_TTY_SIZE];
......@@ -382,9 +442,8 @@ comsat_main (int fd)
char *path = NULL;
mu_message_qid_t qid;
len = sizeof sin_from;
rdlen = recvfrom (fd, buffer, sizeof buffer, 0,
(struct sockaddr*)&sin_from, &len);
len = sizeof fromaddr;
rdlen = recvfrom (fd, buffer, sizeof buffer, 0, &fromaddr, &len);
if (rdlen <= 0)
{
if (errno == EINTR)
......@@ -393,19 +452,16 @@ comsat_main (int fd)
return 1;
}
if (acl_match (&sin_from))
{
mu_diag_output (MU_DIAG_ALERT, _("DENIED attempt to connect from %s"),
inet_ntoa (sin_from.sin_addr));
return 1;
}
if (check_connection (fd, &fromaddr, len))
return 1;
mu_diag_output (MU_DIAG_INFO,
ngettext ("Received %d byte from %s",
"Received %d bytes from %s", rdlen),
rdlen, inet_ntoa (sin_from.sin_addr));
ngettext ("Received %d byte from %s",
"Received %d bytes from %s", rdlen),
rdlen, inet_ntoa (((struct sockaddr_in*)&fromaddr)->sin_addr));
buffer[rdlen] = 0;
mu_diag_output (MU_DIAG_INFO, "string: %s", buffer);
/* Parse the buffer */
p = strchr (buffer, '@');
......@@ -417,7 +473,13 @@ comsat_main (int fd)
*p++ = 0;
qid = p;
p = strchr (qid, ':');
if (p)
{
*p++ = 0;
path = p;
}
if (find_user (buffer, tty) != SUCCESS)
return 0;
......
......@@ -60,6 +60,7 @@
#include <mailutils/argcv.h>
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
#ifndef INADDR_NONE
# define INADDR_NONE -1
......@@ -77,6 +78,4 @@ extern const char *username;
extern char hostname[];
extern struct daemon_param daemon_param;
extern void read_config (const char *config_file);
int acl_match (struct sockaddr_in *sa_in);
void run_user_action (FILE *tty, const char *cr, mu_message_t msg);
......
......@@ -669,7 +669,7 @@ maildir_qfetch (struct _amd_data *amd, mu_message_qid_t qid)
if (!name)
return EINVAL;
name++;
msg = calloc (1, sizeof(*msg));
msg->file_name = strdup (name);
......