Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 26 Oct 2000 20:54:58 +0200
From:      Gerhard Sittig <Gerhard.Sittig@gmx.net>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   ports/22316: [PATCH] samba port in a jail(2) environment
Message-ID:  <20001026205458.U25237@speedy.gsinet>

next in thread | raw e-mail | index | archive | help

>Number:         22316
>Category:       ports
>Synopsis:       [PATCH] samba port in a jail(2) environment
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-ports
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Oct 26 12:20:02 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Gerhard Sittig
>Release:        FreeBSD 4.1-STABLE i386
>Organization:
in private
>Environment:

FreeBSD with jail(2)ed process groups and services / applications
trying to access the "localhost loopback".  Mostly this is done
for internal communication with helpers or subsystems.

This particular PR deals with FreeBSD 4.1-S and the Samba-2.0.7
port.  But the topic is relevant for other software, too.

>Description:

FreeBSD provides a jail(2) functionality which separates process
groups from each other and offers only those resources for
manipulation which are unique to this jail (i.e. when it's safe
and others are not harmed by the manipulation).

Unfortunately this means that some things "don't work as expected
in a normal UNIX environment".  Since some resources are handled
by the "host" the jailed processes are not allowed to manipulate
or even access them.

Samba, wwwoffle, and squid are some of the applications assuming
that "every machine I run on has an interface named localhost
with the address of 127.0.0.1 and it's always possible to bind to
it".  That's why they don't run well in a jail(2).  Some don't
start up successfully, some do and fail to operate on incoming
requests.

>How-To-Repeat:

Set up a jail as described in jail(8), install samba in it and
try the following sequence:

  smbclient -L `hostname` -U%
  tail /var/log/log.smb

It will spit out error messages about failed connection attempts
and the log shows that IPC won't work since a UDP socket cannot
be established at address 127.0.0.1.  Editing smb.conf and adding
options "bind interfaces only", "interfaces" and "socket address"
don't help here (what are they meant for when there's always some
implicit "localhost" binding?).

Searching in the freebsd-ports ML archive (via the web interface)
for some combination of "jail", "loopback", "localhost", "port"
didn't turn up any hits.  But I doubt that I'm the first one to
step over this effect ...

>Fix:

I understand that jail(2) can _never_ provide address 127.0.0.1
into the locked in processes group (without virtualizing this lo0
interface, which is too much of an effort and contradicts the
goal and design of the mechanism -- it was never meant to be a
virtual machine).

So all that's left is to bind the applications' sockets to the
"official" / "external" address of the jail.  But since some feel
it to be quite unusual to not have a localhost interface, they
start hardcoding this name all over the place and even don't ask
the user if he wants it. :(

The patch cited below tries to
- bundle all the names and addresses in a single spot
- have all the previously hardcoded references use the new
  declaration
- produce a declaration with the previously used names and
  addresses for the straight case and fall off the "localhost"
  name and "127.0.0.1" address when the application is probably
  run in a jail to use an available interface

This decision is carried out at compile time.  Sorry, but without
the application's help there's no runtime switch possible.  And
it seems to be not this necessary, I feel the app will get
compiled (from the ports) on the machine to be run at.


This particular patch will help samba to run successfully in a
jail.  And it could provide a skeleton for other ports, too (I'm
positive about squid and wwwoffle having the very same problem,
but samba is the one I solved in the proper and clean(? see
below) way to publish it here).

But I'm not sure if other solutions are more appropriate in the
long run:  Maybe a jailed environment should export the
definition in netinet/in.h customized to local circumstances
already?  But it would disqualify the machine for cross compiling
and binary distribution.  Hmmm ...

The only painless (from the application POV) solution would be
127.0.0.1 support in jails.  Especially when one considers the
many ways developers come up with about how to spell "localhost".
Keep in mind that providing any other interface different from
the "official" jail interface with an address like 127.0.0.2 or
the like in future jail versions to have a local loopback again
would still require the below cited special treatment ...


The patch needs correction from somebody more familiar with the
port than me in terms of where to invoke the loopback.h creation.
Without the hack in the CHECK target and with the loopback.h
target only it won't happen before compiling the sources -- and
compilation will fail due to the missing header file.  And I
failed to identify which programs (i.e. targets) depend on this
particular #include ("include/includes.h").

The mkloopback.sh script is not streamlined but should be of
general enough form to maybe get incorporated (in the current or
any better, faster, more portable, more flexible or more embedded
form) into the ports base somewhere when it turns out that other
ports would benefit from it, too.  Writing to stdout and
redirecting this code into the header file in the particular port
provides the needed flexibility to not clobber existing files.
Maybe the #define identifier for one time inclusion needs to be a
parameter / an option.  And it shouldn't matter how the
surrounding jail gets detected or where the IP and hostname are
derived from, since this logic is in the ports base the concrete
port doesn't have to know about the involved methods.  Although
one should keep in mind that a /proc filesystem might not always
be there -- that is why I decided to use the expensive way with
lots of external programs.  dig(1) would be terrible to parse,
dnsip - having the most appropriate output format for this task -
is not available everywhere (yet?).  BTW: Can a jail have more
than one IP or none at all?  I don't think so.  But "normal"
hosts could ...


I understand that the samba development team is not aware of the
"problem" described in this PR and neither is it in desparate
need of a fix for their overall tarball.  But they could as well
incorporate the "bundling" and deliver a loopback.h file with the
"localhost", "127.0.0.1" and "0x7f000001" assumptions.  This
would degrade the FreeBSD special hook into overwriting the
header file somewhere in between "make extract", "make patch",
"make configure" and "make all".  But for judging this I'm not
enough of a ports expert.  And I didn't contact the Samba team on
this yet since I wanted to learn before whether this solution
provided here for discussion is a viable way.


diff -uwb -r -N Makefile.in Makefile.in
--- Makefile.in	Tue Oct 24 09:23:31 2000
+++ Makefile.in	Thu Oct 26 14:41:50 2000
@@ -293,7 +293,7 @@
 .SUFFIXES:
 .SUFFIXES: .c .o .po .po32
 
-CHECK:
+CHECK: $(srcdir)/include/loopback.h	# YES, it's dirty ...
 	@echo "Using FLAGS = $(FLAGS)"
 	@echo "Using FLAGS32 = $(FLAGS32)"
 	@echo "Using LIBS = $(LIBS)"
@@ -576,6 +576,9 @@
 $(srcdir)/include/stamp-h.in: @MAINT@ $(srcdir)/acconfig.h $(srcdir)/configure.in
 	cd $(srcdir) && $(AUTOHEADER)
 	@date -u > $@
+
+$(srcdir)/include/loopback.h:
+	cd $(srcdir) && $(SHELL) ./script/mkloopback.sh > $@
 
 # automatic dependency tracking rules
 .deps/.dummy:
diff -uwb -r -N include/includes.h include/includes.h
--- include/includes.h	Wed Apr 26 01:06:46 2000
+++ include/includes.h	Thu Oct 26 13:54:01 2000
@@ -788,9 +788,11 @@
 #define SEEK_SET 0
 #endif
 
-#ifndef INADDR_LOOPBACK
-#define INADDR_LOOPBACK 0x7f000001
-#endif
+/*
+ * NO, 127.0.0.1 is *NOT* always there!
+ * and how many ways do you know of to spell "localhost"?
+ */
+#include "loopback.h"
 
 #ifndef INADDR_NONE
 #define INADDR_NONE 0xffffffff
diff -uwb -r -N lib/access.c lib/access.c
--- lib/access.c	Wed Jul 21 03:25:08 1999
+++ lib/access.c	Thu Oct 26 13:50:31 2000
@@ -202,7 +202,7 @@
 	client[1] = caddr;  
 
 	/* if it is loopback then always allow unless specifically denied */
-	if (strcmp(caddr, "127.0.0.1") == 0) {
+	if (strcmp(caddr, INTEXT_LOOPBACK) == 0) {
 		if (deny_list && 
 		    list_match(deny_list,(char *)client,client_match)) {
 			return False;
diff -uwb -r -N lib/interface.c lib/interface.c
--- lib/interface.c	Wed Oct 13 07:26:48 1999
+++ lib/interface.c	Thu Oct 26 13:50:41 2000
@@ -175,7 +175,7 @@
 
 	ipzero = *interpret_addr2("0.0.0.0");
 	allones_ip = *interpret_addr2("255.255.255.255");
-	loopback_ip = *interpret_addr2("127.0.0.1");
+	loopback_ip = *interpret_addr2(INTEXT_LOOPBACK);
 
 	if (probed_ifaces) {
 		free(probed_ifaces);
diff -uwb -r -N param/loadparm.c param/loadparm.c
--- param/loadparm.c	Tue Oct 24 09:23:31 2000
+++ param/loadparm.c	Thu Oct 26 13:49:42 2000
@@ -1004,7 +1004,7 @@
 
 #ifdef WITH_LDAP
   /* default values for ldap */
-  string_set(&Globals.szLdapServer, "localhost");
+  string_set(&Globals.szLdapServer, INNAME_LOOPBACK);
   Globals.ldap_port=389;
 #endif /* WITH_LDAP */
 
@@ -2826,7 +2826,7 @@
 
   if (in_client && Globals.bWINSsupport) {
 
-    string_set(&Globals.szWINSserver, "127.0.0.1");
+    string_set(&Globals.szWINSserver, INTEXT_LOOPBACK);
 
   }
 
diff -uwb -r -N printing/print_cups.c printing/print_cups.c
--- printing/print_cups.c	Tue Oct 19 06:36:42 1999
+++ printing/print_cups.c	Thu Oct 26 13:48:22 2000
@@ -171,7 +171,7 @@
 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
                      "attributes-natural-language", NULL, language->language);
 
-	snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", name);
+	snprintf(uri, sizeof(uri), "ipp://" INNAME_LOOPBACK "/printers/%s", name);
 
 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
                      "printer-uri", NULL, uri);
diff -uwb -r -N script/mkloopback.sh script/mkloopback.sh
--- script/mkloopback.sh	Thu Jan  1 01:00:00 1970
+++ script/mkloopback.sh	Thu Oct 26 13:39:49 2000
@@ -0,0 +1,53 @@
+#!/bin/sh
+# ----- mkloopback.sh -------------------------------------------
+# aid in making samba (2.0.7) run in a jail(2)ed environment;
+# other ports (squid, wwwoffle) are known to have the same problem
+
+ME=`basename $0`
+
+# defaults (Samba's original assumption)
+LO_HOSTNAME="localhost."
+
+# see if we're jailed -- then there will be no lo0 available
+PSSTAT=`ps $$ | tail -1 | awk '{ print $3 }'`
+case "$PSSTAT" in
+*J*)	LO_HOSTNAME=`hostname`;;
+esac
+
+# now determine an address to use
+LO_ADDR_TXT=`host $LO_HOSTNAME | sed 's/.* has address //' | sort -u`
+if [ -z "$LO_ADDR_TXT" ]; then
+	echo "$ME: warning: " \
+		"no IP address found, bailing out ..." 1>&2
+	exit 1
+fi
+if [ `echo "$LO_ADDR_TXT" | wc -w` -ne 1 ]; then
+	echo "$ME: warning: " \
+		"more than one IP address found ($LO_ADDR_TXT), " \
+		"using the first value only ..." 1>&2
+	LO_ADDR_TXT=`echo $LO_ADDR_TXT | sed 's/[ 	].*$//'`
+fi
+
+# make the dotted quad a 32bit int (hex) value
+LO_ADDR_NUM=`echo $LO_ADDR_TXT | tr '.' ' '`
+LO_ADDR_NUM=`printf "0x%02X%02X%02X%02X" $LO_ADDR_NUM`
+
+# create an #include file
+cat <<E_O_F
+#ifndef _LOOPBACK_H_
+#define _LOOPBACK_H_
+
+/* quiet a warning about "redefined" against netinet/in.h */
+#ifdef	INADDR_LOOPBACK
+#undef	INADDR_LOOPBACK
+#endif	/* INADDR_LOOPBACK */
+
+/* maybe loopback is not always at localhost/127.0.0.1 */
+#define	INNAME_LOOPBACK	"$LO_HOSTNAME"
+#define	INTEXT_LOOPBACK	"$LO_ADDR_TXT"
+#define	INADDR_LOOPBACK	$LO_ADDR_NUM
+
+#endif /* _LOOPBACK_H_ */
+E_O_F
+
+# ----- E O F ---------------------------------------------------
diff -uwb -r -N smbd/oplock.c smbd/oplock.c
--- smbd/oplock.c	Wed Apr 26 01:07:11 2000
+++ smbd/oplock.c	Thu Oct 26 13:50:09 2000
@@ -259,7 +259,7 @@
   /* Validate message from address (must be localhost). */
   if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
     DEBUG(0,("receive_local_message: invalid 'from' address \
-(was %lx should be 127.0.0.1\n", (long)from.sin_addr.s_addr));
+(was %lx should be " INTEXT_LOOPBACK "\n", (long)from.sin_addr.s_addr));
    return False;
   }
 
diff -uwb -r -N utils/smbpasswd.c utils/smbpasswd.c
--- utils/smbpasswd.c	Wed Apr 26 01:07:16 2000
+++ utils/smbpasswd.c	Thu Oct 26 13:50:55 2000
@@ -507,7 +507,7 @@
 	 * localhost).
 	 */	
 	if (remote_machine == NULL) {
-		remote_machine = "127.0.0.1";
+		remote_machine = INTEXT_LOOPBACK;
 	}
 
 
diff -uwb -r -N web/diagnose.c web/diagnose.c
--- web/diagnose.c	Mon Feb 22 20:27:05 1999
+++ web/diagnose.c	Thu Oct 26 13:49:34 2000
@@ -32,7 +32,7 @@
 	struct in_addr *ip_list;
 
 	if ((fd = open_socket_in(SOCK_DGRAM, 0, 3,
-				 interpret_addr("127.0.0.1"), True)) != -1) {
+				 interpret_addr(INTEXT_LOOPBACK), True)) != -1) {
 		if ((ip_list = name_query(fd, "__SAMBA__", 0, 
 					  True, True, loopback_ip,
 					  &count,0)) != NULL) {
@@ -57,7 +57,7 @@
 	if (!cli_initialise(&cli))
 		return False;
 
-	if (!cli_connect(&cli, "localhost", &loopback_ip)) {
+	if (!cli_connect(&cli, INNAME_LOOPBACK, &loopback_ip)) {
 		cli_shutdown(&cli);
 		return False;
 	}
diff -uwb -r -N web/swat.c web/swat.c
--- web/swat.c	Wed Apr 26 01:07:17 2000
+++ web/swat.c	Thu Oct 26 13:50:48 2000
@@ -709,7 +709,7 @@
 	} else if (am_root()) {
 		host = NULL;
 	} else {
-		host = "127.0.0.1";
+		host = INTEXT_LOOPBACK;
 	}
 
 	/*


virtually yours   82D1 9B9C 01DC 4FB4 D7B4  61BE 3F49 4F77 72DE DA76
Gerhard Sittig   true | mail -s "get gpg key" Gerhard.Sittig@gmx.net
-- 
     If you don't understand or are scared by any of the above
             ask your parents or an adult to help you.

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001026205458.U25237>