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@???>
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
From aac11fa66a9f4a2b7417d328bd9b0d59666bd7c5 Mon Sep 17 00:00:00 2001
From: Phil Pennock <pdp@???>
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