Subject: Re: symlink complaints in /etc/security
To: Perry E. Metzger <perry@piermont.com>
From: Luke Mewburn <lukem@NetBSD.org>
List: tech-security
Date: 12/08/2003 14:15:14
--63tCqOYFH7xKgZE5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sun, Dec 07, 2003 at 09:16:28PM -0500, Perry E. Metzger wrote:
  | >  since it doesn't involve adding more special cases to mtree,
  | 
  | Well, it does require that we rig mtree to handle this, or somehow
  | build a script that does it for mtree....
  |
  | So how do we do it?

As I mentioned, using awk on the output of "mtree -C -K all" may be
sufficient, although it starts to get slightly messy.


Alternatively, we could implement mtree -M (? - merge) to allow
entries to be replaced with ones of a different type.
In /etc/security we'd then do something like:
	cat $special_files | mtree -C -K all -M > ${SECUREDIR}/specials
and use ${SECUREDIR}/specials appropriately.

Currently spec.c::replacenode() in mtree forbids this (and that
is a sane default to retain); -M could relax that check. 
The special case we need to consider is if "type==dir && child!=NULL".
For example, as special has
	./etc/mail                  type=dir mode=0755
	./etc/mail/aliases          type=file mode=0644
	./etc/mail/helpfile         type=file mode=0444
if you replace /etc/mail with a symlink to /var/chroot/mail and add
the following to special.local
	./etc/mail                  type=link link=/var/chroot/mail
	./var                       type=dir mode=0755
	./var/chroot                type=dir mode=0755
	./var/chroot/mail           type=dir mode=0755
	./var/chroot/mail/etc       type=dir mode=0755
	./var/chroot/mail/aliases   type=file mode=0644
	./var/chroot/mail/helpfile  type=file mode=0644
the you don't want ./etc/mail/{aliases,helpfile} in the final
specfile.  

Here's a proof of concept diff to mtree.  Care to try it out on your
system with special.local whacked appropriately (and _without_ mtree -L)?


Cheers,
Luke.

--63tCqOYFH7xKgZE5
Content-Type: text/plain; charset=us-ascii
Content-Description: mtree-M.diff
Content-Disposition: attachment; filename=difz

? difz
Index: extern.h
===================================================================
RCS file: /cvsroot/src/usr.sbin/mtree/extern.h,v
retrieving revision 1.28
diff -p -p -u -r1.28 extern.h
--- extern.h	27 Oct 2003 00:12:44 -0000	1.28
+++ extern.h	8 Dec 2003 03:12:35 -0000
@@ -70,7 +70,7 @@ const char *rlink(const char *);
 int	 verify(void);
 
 extern int	dflag, eflag, iflag, lflag, mflag, rflag, sflag, tflag, uflag;
-extern int	Wflag;
+extern int	Mflag, Wflag;
 extern size_t	mtree_lineno;
 extern u_int32_t crc_total;
 extern int	ftsoptions, keys;
Index: mtree.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/mtree/mtree.c,v
retrieving revision 1.30
diff -p -p -u -r1.30 mtree.c
--- mtree.c	7 Aug 2003 11:25:36 -0000	1.30
+++ mtree.c	8 Dec 2003 03:12:36 -0000
@@ -73,7 +73,7 @@ main(int argc, char **argv)
 	dir = NULL;
 	init_excludes();
 
-	while ((ch = getopt(argc, argv, "cCdDeE:f:I:ik:K:lLmN:p:PrR:s:tuUWxX:"))
+	while ((ch = getopt(argc, argv, "cCdDeE:f:I:ik:K:lLmMN:p:PrR:s:tuUWxX:"))
 	    != -1) {
 		switch((char)ch) {
 		case 'c':
@@ -124,6 +124,9 @@ main(int argc, char **argv)
 			break;
 		case 'm':
 			mflag = 1;
+			break;
+		case 'M':
+			Mflag = 1;
 			break;
 		case 'N':
 			if (! setup_getid(optarg))
Index: spec.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/mtree/spec.c,v
retrieving revision 1.53
diff -p -p -u -r1.53 spec.c
--- spec.c	17 Nov 2003 00:02:33 -0000	1.53
+++ spec.c	8 Dec 2003 03:12:36 -0000
@@ -92,6 +92,7 @@ __RCSID("$NetBSD: spec.c,v 1.53 2003/11/
 #include "pack_dev.h"
 
 size_t	mtree_lineno;			/* Current spec line number */
+int	Mflag;				/* Merge duplicate entries */
 int	Wflag;				/* Don't "whack" permissions */
 
 static	dev_t	parsedev(char *);
@@ -407,11 +408,24 @@ static void
 replacenode(NODE *cur, NODE *new)
 {
 
-	if (cur->type != new->type)
-		mtree_err("existing entry for `%s', type `%s' does not match type `%s'",
-		    cur->name, nodetype(cur->type), nodetype(new->type));
 #define REPLACE(x)	cur->x = new->x
 #define REPLACESTR(x)	if (cur->x) free(cur->x); cur->x = new->x
+	if (cur->type != new->type) {
+		if (Mflag) {
+				/*
+				 * merge entries with different types; we
+				 * don't want children retained in this case.
+				 */
+			REPLACE(type);
+			cur->child = NULL;
+		} else {
+			mtree_err(
+			    "existing entry for `%s', type `%s'"
+			    " does not match type `%s'",
+			    cur->name, nodetype(cur->type),
+			    nodetype(new->type));
+		}
+	}
 
 	REPLACE(st_size);
 	REPLACE(st_mtimespec);

--63tCqOYFH7xKgZE5--