Regarding the "cannot execute binary file" error:
As previously noted, on my (gentoo) system this is due to using the
version of su from the 'shadow' package rather than GNU su. I've fixed
this problem and attached a patch,
dchroot-0.11-no_gnu_su.patch
which #ifdef's out the problematic bits. Debian (and other) users with
the GNU version of su should define the preprocessor symbol WITH_GNU_SU.
During fixing this problem, another became apparent: dchroot cannot
pass arbitrary sets of arguments to the shell because it grabs any
argument starting with a '-'. To fix this I've implemented the
canonical '--' option to allow all subsequent arguments to pass through
to the chrooted shell. See
dchroot-0.11-option_fix.patch
for the fix.
Hope these are helpful,
Chris F.
--- dchroot.c.old 2005-04-30 02:09:35.000000000 +1000
+++ dchroot.c 2005-05-01 22:37:26.000000000 +1000
@@ -199,15 +199,42 @@
return -1;
} else if (pid == 0) {
- if (!argv) {
- /* Will execute a shell in the new chroot. */
+ int cmdnum = 0;
+ int argc = 0;
- cmd = malloc(sizeof(char *) * 4);
+ /* estimate length of command list to su */
+ if (!argv) {
+ argc = 4;
+ } else {
+ while (argv[argc] != NULL) {
+ argc++;
+ }
+ argc += 5;
+ }
+ cmd = malloc(sizeof(char *) * argc);
+
+ if (!cmd) {
+ dchroot_perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ cmd[cmdnum++] = "/bin/su";
+
+ if (opts.dir[0] == '\0') {
+ /* /bin/su, -, username, ... */
+ cmd[cmdnum++] = "-";
+ } else {
+#ifdef WITH_GNU_SU
+ /* /bin/su, -p, username, ... */
+ cmd[cmdnum++] = "-p";
+#endif
+ /* /bin/su, username, ... */
+ /* su from shadow package doesn't know about -p option. */
+ }
+ cmd[cmdnum++] = username;
- if (!cmd) {
- dchroot_perror("malloc");
- exit(EXIT_FAILURE);
- }
+ if (!argv) {
+ /* Will execute a shell in the new chroot. */
if (!opts.quiet) {
printf("Executing shell in '%s' chroot.\n",
@@ -215,61 +242,32 @@
fflush(NULL);
}
- cmd[0] = "/bin/su";
-
- if (opts.dir[0] == '\0') {
- /* /bin/su, -, username, NULL */
- cmd[1] = "-";
- } else {
- /* /bin/su, -p, username, NULL */
- cmd[1] = "-p";
- }
- cmd[2] = username;
- cmd[3] = NULL;
+ cmd[cmdnum++] = NULL;
} else {
- /* Will execute the command in argv[] in the
+ /* Will execute the commands in argv[] in the
* new chroot.
*/
- int argc = 0;
- int i = 0, j = 0;
+ int i = 0;
+ int shcmdstart = 0;
- while (argv[i++] != NULL) {
- argc++;
- }
-
- cmd = malloc(sizeof(char *) * (argc + 5));
-
- if (!cmd) {
- dchroot_perror("malloc");
- exit(EXIT_FAILURE);
- }
-
- i = 0;
- cmd[i++] = "/bin/su";
-
- if (opts.dir[0] == '\0') {
- /* /bin/su - username argv[0] argv[1] ... */
- cmd[i++] = "-";
- } else {
- /* /bin/su -p username argv[0] argv[1] ... */
- cmd[i++] = "-p";
- }
-
- cmd[i++] = username;
- cmd[i++] = "--";
-
- while (argv[j] != NULL) {
- cmd[i++] = argv[j];
- j++;
+#ifdef WITH_GNU_SU
+ /* prevent gnu su from grabbing options inteded for the shell */
+ cmd[cmdnum++] = "--";
+#endif
+
+ shcmdstart = cmdnum + 1;
+ while (argv[i] != NULL) {
+ cmd[cmdnum++] = argv[i];
+ i++;
}
- cmd[i] = NULL;
+ cmd[cmdnum] = NULL;
if (!opts.quiet) {
printf("(%s) ", chroot_to->name);
- i = 4;
+ i = shcmdstart;
while (cmd[i]) {
printf("%s ", cmd[i]);
i++;
--- dchroot.c.mid 2005-05-01 22:49:30.000000000 +1000
+++ dchroot.c 2005-05-02 00:09:56.000000000 +1000
@@ -250,14 +250,14 @@
*/
int i = 0;
- int shcmdstart = 0;
+ int sh_cmd_start = 0;
#ifdef WITH_GNU_SU
/* prevent gnu su from grabbing options inteded for the shell */
cmd[cmdnum++] = "--";
#endif
- shcmdstart = cmdnum + 1;
+ sh_cmd_start = cmdnum;
while (argv[i] != NULL) {
cmd[cmdnum++] = argv[i];
i++;
@@ -267,7 +267,7 @@
if (!opts.quiet) {
printf("(%s) ", chroot_to->name);
- i = shcmdstart;
+ i = sh_cmd_start;
while (cmd[i]) {
printf("%s ", cmd[i]);
i++;
@@ -345,11 +345,13 @@
static void usage(char *cmd)
{
- printf("Usage: %s [OPTION...] [COMMAND]\n", cmd);
- printf
- ("Execute COMMAND under a different root filesystem, "
- "or if no command is given\n");
- printf("invoke a shell.\n");
+ printf("Usage: %s [OPTION...] [[--] COMMAND]\n", cmd);
+ printf("\n");
+ printf("Execute COMMAND under a different root filesystem, "
+ "or if no command is given\n");
+ printf("invoke a shell. Using -- causes all subsequent input "
+ "to go to the shell\n");
+ printf("in the chroot.\n");
printf("\n");
printf(" -a Execute in all known chroots.\n");
printf(" -c newroot Execute in specified chroot.\n");
@@ -359,7 +361,6 @@
printf(" -q Be quiet.\n");
printf(" -h Print help message.\n");
printf(" -V Print program version.\n");
-
}
@@ -369,9 +370,10 @@
int rv = 0;
char **cmd;
int index = 1;
+ int opts_finished = 0;
struct passwd *pwd;
- while (argv[index] && argv[index][0] == '-') {
+ while (argv[index] && argv[index][0] == '-' && ! opts_finished) {
if (argv[index][1] == '\0' || argv[index][2] != '\0') {
dchroot_printf("Unknown option '-%c%c'.\n",
@@ -394,9 +396,7 @@
}
break;
case 'l':
- if ((chroots = read_chroots(CHROOTS_CONF)) == NULL) {
- printf("No chroots found.\n");
- } else {
+ if ((chroots = read_chroots(CHROOTS_CONF)) != NULL) {
list_chroots(chroots);
printf("\n");
}
@@ -413,6 +413,9 @@
usage(argv[0]);
exit(EXIT_SUCCESS);
break;
+ case '-':
+ opts_finished = 1;
+ break;
default:
dchroot_printf("Unknown option '%s'.\n",
argv[index]);
@@ -425,6 +428,7 @@
usage(argv[0]);
exit(EXIT_FAILURE);
}
+
index++;
}