Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: exim: users

mailman in a jail(8) (for people without FreeBSD experience: think chroot(8))

 

 

exim users RSS feed   Index | Next | Previous | View Threaded


ml+exim at wzff

Feb 19, 2012, 6:06 AM

Post #1 of 3 (233 views)
Permalink
mailman in a jail(8) (for people without FreeBSD experience: think chroot(8))

Hi folks,

I've installed mailman in a FreeBSD-jail(8) (much like chroot(8)-jails,
but can't be left that easily via fchdir etc.), and now I have the
problem that I can't reach mailman (version 2, version 3 would have
LMTP, which would eliminate the entire problem). Exim, trying to be
secure software is refusing to run the jail(8) command as root, which
means I am having a hard time to pass things into the jail via a pipe
transport.

I see a few more or less ugly kludges around the problem:

- make a setuid wrapper that runs mailman in the jail.
- run another exim instance in the jail as some kind of LMTP or SMTP
wrapper around mailman v2

Does someone know a better way (e.g. a designated LMTP wrapper
implementation)?


Best regards,

Moritz

--
## List details at https://lists.exim.org/mailman/listinfo/exim-users
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/


pdp at exim

Feb 20, 2012, 12:13 AM

Post #2 of 3 (211 views)
Permalink
Re: mailman in a jail(8) (for people without FreeBSD experience: think chroot(8)) [In reply to]

On 2012-02-19 at 15:06 +0100, Moritz Wilhelmy wrote:
> I've installed mailman in a FreeBSD-jail(8) (much like chroot(8)-jails,
> but can't be left that easily via fchdir etc.), and now I have the
> problem that I can't reach mailman (version 2, version 3 would have
> LMTP, which would eliminate the entire problem). Exim, trying to be
> secure software is refusing to run the jail(8) command as root, which
> means I am having a hard time to pass things into the jail via a pipe
> transport.
>
> I see a few more or less ugly kludges around the problem:
>
> - make a setuid wrapper that runs mailman in the jail.
> - run another exim instance in the jail as some kind of LMTP or SMTP
> wrapper around mailman v2
>
> Does someone know a better way (e.g. a designated LMTP wrapper
> implementation)?

If you're using Jails for security, you might want to consider whether
or not the MTA should run inside a jail too.

As long as you're not doing so, try the patch (that's both below and
attached). I don't currently have any Jails setup, so can't actually
*test* it, but it does compile. *cough* On FreeBSD 7, and there may
have been incompatible changes in later releases.

This is relative to git head, but should apply back for a release or two
without issues, I think.

Please let me know how you get on, if you try it, so we can consider it
for inclusion in the next release (and you don't get stuck maintaining a
patch locally).

Regards,
-Phil

From aac11fa66a9f4a2b7417d328bd9b0d59666bd7c5 Mon Sep 17 00:00:00 2001
From: Phil Pennock <pdp [at] exim>
Date: Mon, 20 Feb 2012 03:08:05 -0500
Subject: [PATCH] jail_identifier support for pipe transport

---
src/OS/os.c-FreeBSD | 82 +++++++++++++++++++++++++++++++++++++++++++++
src/OS/os.h-FreeBSD | 9 +++++
src/src/transports/pipe.c | 53 +++++++++++++++++++++++++++--
src/src/transports/pipe.h | 1 +
4 files changed, 142 insertions(+), 3 deletions(-)
create mode 100644 src/OS/os.c-FreeBSD

diff --git a/src/OS/os.c-FreeBSD b/src/OS/os.c-FreeBSD
new file mode 100644
index 0000000..3b9fa14
--- /dev/null
+++ b/src/OS/os.c-FreeBSD
@@ -0,0 +1,82 @@
+#ifndef COMPILE_UTILITY /* Utilities don't need special code */
+
+#ifdef HAVE_FREEBSD_JAIL
+
+#include <sys/sysctl.h>
+
+/* Given a string, search system jail list to find the jid for that string.
+
+Returns:
+ -1 unable to extract jail identifier
+ >= 0 jail identifier
+*/
+
+int
+parse_jail_identifier(uschar *identifier)
+{
+/* Logic borrowed from FreeBSD 7's src/usr.sbin/jls/jls.c */
+/* Later releases might permit matching on IPv6? */
+struct xprison *xp;
+struct in_addr in;
+size_t i, len;
+int jid;
+uschar *store_reset_point;
+
+if (!identifier)
+ return -1;
+
+if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
+ {
+ DEBUG(D_any)
+ debug_printf("PJI: sysctlbyname(): security.jail.list (1:len): %s\n", strerror(errno));
+ return -1;
+ }
+if (len < sizeof(*xp))
+ {
+ DEBUG(D_any)
+ debug_printf("PJI: length too short, aborting for safety [%ld]\n", (long) len);
+ return -1;
+ }
+
+store_reset_point = store_get(0);
+xp = (struct xprison *) store_get(len);
+if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1)
+ {
+ DEBUG(D_any)
+ debug_printf("PJI: sysctlbyname(): security.jail.list (2:fetch): %s\n", strerror(errno));
+ return -1;
+ }
+if (len < sizeof(*xp) || len % sizeof(*xp) ||
+ xp->pr_version != XPRISON_VERSION)
+ {
+ int i=0;
+ if (len >= sizeof(*xp))
+ i = xp->pr_version;
+ DEBUG(D_any)
+ debug_printf("PJI: kernel ABI changed from Exim, not mutually compatible.\n"
+ " sizeof(struct xprison)=%ld len=%ld pr_version=%d XPRISON_VERSION=%d\n",
+ (long) sizeof(*xp), (long) len, i, XPRISON_VERSION);
+ return -1;
+ }
+
+jid = -1;
+for (i = 0; i < len / sizeof(*xp); i++)
+ {
+ in.s_addr = ntohl(xp->pr_ip);
+ if (streqic(identifier, US xp->pr_host) ||
+ streqic(identifier, US xp->pr_path) ||
+ streqic(identifier, US inet_ntoa(in)))
+ {
+ jid = xp->pr_id;
+ break;
+ }
+ xp++;
+ }
+
+store_reset(store_reset_point);
+return jid;
+}
+#endif /* HAVE_FREEBSD_JAIL */
+
+/* vim: set ft=c : */
+#endif /* COMPILE_UTILITY */
diff --git a/src/OS/os.h-FreeBSD b/src/OS/os.h-FreeBSD
index c5ed042..9ed2080 100644
--- a/src/OS/os.h-FreeBSD
+++ b/src/OS/os.h-FreeBSD
@@ -8,6 +8,15 @@
#define HAVE_SRANDOMDEV
#define HAVE_ARC4RANDOM

+#ifndef COMPILE_UTILITY
+# if __FreeBSD__ >= 7
+# define HAVE_FREEBSD_JAIL
+# include <sys/param.h>
+# include <sys/jail.h>
+int parse_jail_identifier(unsigned char *);
+# endif
+#endif
+
typedef struct flock flock_t;

/* End */
diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c
index 15714f3..e1000c9 100644
--- a/src/src/transports/pipe.c
+++ b/src/src/transports/pipe.c
@@ -43,6 +43,10 @@ optionlist pipe_transport_options[] = {
(void *)offsetof(pipe_transport_options_block, freeze_signal) },
{ "ignore_status", opt_bool,
(void *)offsetof(pipe_transport_options_block, ignore_status) },
+ #ifdef HAVE_FREEBSD_JAIL
+ { "jail_identifier", opt_stringptr,
+ (void *)offsetof(pipe_transport_options_block, jail_identifier) },
+ #endif
{ "log_defer_output", opt_bool | opt_public,
(void *)offsetof(transport_instance, log_defer_output) },
{ "log_fail_output", opt_bool | opt_public,
@@ -106,6 +110,7 @@ pipe_transport_options_block pipe_transport_option_defaults = {
mac_expanded_string(EX_CANTCREAT),
NULL, /* check_string */
NULL, /* escape_string */
+ NULL, /* jail_identifier */
022, /* umask */
20480, /* max_output */
60*60, /* timeout */
@@ -123,7 +128,6 @@ pipe_transport_options_block pipe_transport_option_defaults = {
};


-
/*************************************************
* Setup entry point *
*************************************************/
@@ -131,7 +135,8 @@ pipe_transport_options_block pipe_transport_option_defaults = {
/* Called for each delivery in the privileged state, just before the uid/gid
are changed and the main entry point is called. In a system that supports the
login_cap facilities, this function is used to set the class resource limits
-for the user. It may also re-enable coredumps.
+for the user. It may also re-enable coredumps. On FreeBSD, it might switch
+into a jail.

Arguments:
tblock points to the transport instance
@@ -158,6 +163,49 @@ gid = gid;
errmsg = errmsg;
ob = ob;

+#ifdef HAVE_FREEBSD_JAIL
+if (ob->jail_identifier)
+ {
+ int jrc, jid = -1;
+ long jtmp;
+ uschar *jail_str, *jend;
+
+ jail_str = expand_string(ob->jail_identifier);
+ if (jail_str)
+ {
+ jtmp = Ustrtol(jail_str, &jend, 10);
+ if (jend == jail_str)
+ {
+ /* os.c provides this */
+ jid = parse_jail_identifier(jail_str);
+ DEBUG(D_transport)
+ debug_printf("jail setup: jail identifier \"%s\" -> %d%s\n",
+ jail_str, jid,
+ jid < 0 ? " (IGNORED)" : "");
+ }
+ else if (jtmp > INT_MAX || jtmp < 0)
+ {
+ log_write(0, LOG_MAIN,
+ "jail_identifier \"%s\" not integer >= 0", jail_str);
+ return DEFER;
+ }
+ else
+ jid = (int) jtmp;
+ }
+
+ if (jid > -1)
+ {
+ jrc = jail_attach(jid);
+ if (jrc < 0)
+ {
+ log_write(0, LOG_MAIN,
+ "delivery jail_attach(%d) failed: %s", jid, strerror(errno));
+ return DEFER;
+ }
+ }
+ }
+#endif
+
#ifdef HAVE_SETCLASSRESOURCES
if (ob->use_classresources)
{
@@ -196,7 +244,6 @@ return OK;
}


-
/*************************************************
* Initialization entry point *
*************************************************/
diff --git a/src/src/transports/pipe.h b/src/src/transports/pipe.h
index 343628e..ebee5e8 100644
--- a/src/src/transports/pipe.h
+++ b/src/src/transports/pipe.h
@@ -17,6 +17,7 @@ typedef struct {
uschar *temp_errors;
uschar *check_string;
uschar *escape_string;
+ uschar *jail_identifier;
int umask;
int max_output;
int timeout;
--
1.7.9
Attachments: 0001-jail_identifier-support-for-pipe-transport.patch (6.53 KB)


pdp at exim

Feb 20, 2012, 12:17 AM

Post #3 of 3 (210 views)
Permalink
Re: mailman in a jail(8) (for people without FreeBSD experience: think chroot(8)) [In reply to]

On 2012-02-20 at 03:13 -0500, Phil Pennock wrote:
> As long as you're not doing so, try the patch (that's both below and
> attached). I don't currently have any Jails setup, so can't actually
> *test* it, but it does compile. *cough* On FreeBSD 7, and there may
> have been incompatible changes in later releases.
>
> This is relative to git head, but should apply back for a release or two
> without issues, I think.
>
> Please let me know how you get on, if you try it, so we can consider it
> for inclusion in the next release (and you don't get stuck maintaining a
> patch locally).

Forgot to mention: to use, add a "jail_identifier" option to the pipe
transport; it's an expanded string. If the result of expansion is a
number, that's taken to be a Jail ID (jid), per jls(8). If not, some
logic lifted from jls.c is used to walk the sysctl API for getting the
list of jails, and then to try matching by exact case-insensitive string
comparison against the jail hostname, the jail mount path and the jail
IPv4 address. The first match found is used.

-Phil

exim users RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.