Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Jun 2003 03:31:39 -0400
From:      Mike Makonnen <mtm@identd.net>
To:        freebsd-audit@freebsd.org
Cc:        Mark Murray <mark@grondar.org>
Subject:   [CFR] NetBSD's chroot(8) functionality
Message-ID:  <20030602073140.WKWJ3199.pop016.verizon.net@kokeb.ambesa.net>

next in thread | raw e-mail | index | archive | help
Does anyone have any objections to the following change to chroot(8) (the
program, not the syscall)?

Essentially, it allows the user to set a new uid, group, and/or group list when
invoking chroot(8).

Cheers.
-- 
Mike Makonnen  | GPG-KEY: http://www.identd.net/~mtm/mtm.asc
mtm@identd.net | D228 1A6F C64E 120A A1C9  A3AA DAE1 E2AF DBCC 68B9
mtm@FreeBSD.Org| FreeBSD - The Power To Serve

Index: usr.sbin/chroot/chroot.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/chroot/chroot.c,v
retrieving revision 1.8
diff -u -r1.8 chroot.c
--- usr.sbin/chroot/chroot.c	3 May 2003 21:06:36 -0000	1.8
+++ usr.sbin/chroot/chroot.c	2 Jun 2003 05:55:53 -0000
@@ -47,8 +47,12 @@
 
 #include <sys/types.h>
 
+#include <ctype.h>
 #include <err.h>
+#include <grp.h>
+#include <limits.h>
 #include <paths.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -56,29 +60,112 @@
 
 static void usage(void);
 
+char	*user;		/* user to switch to before running program */
+char	*group;		/* group to switch to ... */
+char	*grouplist;	/* group list to switch to ... */
+
 int
 main(argc, argv)
 	int argc;
 	char *argv[];
 {
-	int ch;
-	const char *shell;
-
-	while ((ch = getopt(argc, argv, "")) != -1)
+	struct group	*gp;
+	struct passwd	*pw;
+	char		*endp, *p;
+	const char	*shell;
+	gid_t		gid, gidlist[NGROUPS_MAX];
+	uid_t		uid;
+	int		ch, gids;
+
+	gid = 0;
+	uid = 0;
+	while ((ch = getopt(argc, argv, "G:g:u:")) != -1) {
 		switch(ch) {
+		case 'u':
+			user = optarg;
+			if (*user == '\0')
+				usage();
+			break;
+		case 'g':
+			group = optarg;
+			if (*group == '\0')
+				usage();
+			break;
+		case 'G':
+			grouplist = optarg;
+			if (*grouplist == '\0')
+				usage();
+			break;
 		case '?':
 		default:
 			usage();
 		}
+	}
 	argc -= optind;
 	argv += optind;
 
 	if (argc < 1)
 		usage();
 
+	if (group != NULL) {
+		if (isdigit((unsigned char)*group)) {
+			gid = (gid_t)strtoul(group, &endp, 0);
+			if (*endp != '\0')
+				goto getgroup;
+		} else {
+ getgroup:
+			if ((gp = getgrnam(group)) != NULL)
+				gid = gp->gr_gid;
+			else
+				errx(1, "no such group `%s'", group);
+		}
+	}
+
+	for (gids = 0;
+	    (p = strsep(&grouplist, ",")) != NULL && gids < NGROUPS_MAX; ) {
+		if (*p == '\0')
+			continue;
+
+		if (isdigit((unsigned char)*p)) {
+			gidlist[gids] = (gid_t)strtoul(p, &endp, 0);
+			if (*endp != '\0')
+				goto getglist;
+		} else {
+ getglist:
+			if ((gp = getgrnam(p)) != NULL)
+				gidlist[gids] = gp->gr_gid;
+			else
+				errx(1, "no such group `%s'", p);
+		}
+		gids++;
+	}
+	if (p != NULL && gids == NGROUPS_MAX)
+		errx(1, "too many supplementary groups provided");
+
+	if (user != NULL) {
+		if (isdigit((unsigned char)*user)) {
+			uid = (uid_t)strtoul(user, &endp, 0);
+			if (*endp != '\0')
+				goto getuser;
+		} else {
+ getuser:
+			if ((pw = getpwnam(user)) != NULL)
+				uid = pw->pw_uid;
+			else
+				errx(1, "no such user `%s'", user);
+		}
+	}
+
 	if (chdir(argv[0]) || chroot("."))
 		err(1, "%s", argv[0]);
 
+	if (gids && setgroups(gids, gidlist) == -1)
+		err(1, "setgroups");
+	if (group && setgid(gid) == -1)
+		err(1, "setgid");
+	if (user && setuid(uid) == -1)
+		err(1, "setuid");
+
 	if (argv[1]) {
 		execvp(argv[1], &argv[1]);
 		err(1, "%s", argv[1]);
@@ -94,6 +181,7 @@
 static void
 usage()
 {
-	(void)fprintf(stderr, "usage: chroot newroot [command]\n");
+	(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
+	    "[-u user] newroot [command]\n");
 	exit(1);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030602073140.WKWJ3199.pop016.verizon.net>