Message-Id: <199903041811.SAA92588@out5.ibm.net> From: "Mark E." To: djgpp-workers AT delorie DOT com Date: Thu, 4 Mar 1999 13:11:34 -0500 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: chroot patches v4 X-mailer: Pegasus Mail for Win32 (v3.01d) Reply-To: djgpp-workers AT delorie DOT com Below are my latest chroot patches. I'm hoping they are complete and correct. *** include/libc/root.h.orig Sun Feb 28 14:25:36 1999 --- include/libc/root.h Sun Feb 28 14:28:54 1999 *************** *** 0 **** --- 1,16 ---- + /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ + #ifndef __djgpp_libc_root_h + #define __djgpp_libc_root_h + + #define ROOT_ENV "ROOT" + #define CHROOT_ENV "CHROOT_UNIX" + + extern char __djgpp_root[]; + extern int __djgpp_root_len; + + int chroot (const char *path); + + char *__delete_root (char *path); + + #endif + *** src/libc/compat/unistd/chroot.c.orig Sun Feb 28 14:25:18 1999 --- src/libc/compat/unistd/chroot.c Thu Mar 4 12:17:56 1999 *************** *** 0 **** --- 1,148 ---- + #include + #include + #include + #include + #include + #include + #include + #include + + static int chroot_bss_count = -1; + + unsigned int __chroot_flags = __CHROOT_UNIX_MODE_FLAG; + static unsigned int old_flags; + + char __djgpp_root[PATH_MAX + 1] = { '\0' }; + int __djgpp_root_len = 0; + + + int + chroot (const char *path) + { + char buf[PATH_MAX+1]; + char *to = __djgpp_root; + char *from = buf; + int unix_emu; + int path_len; + + if ((path_len = strlen(path)) > PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + if (chroot_bss_count != __bss_count) + { + chroot_bss_count = __bss_count; + old_flags = ~0; + } + + unix_emu = __chroot_flags & __CHROOT_UNIX_MODE_FLAG; + + /* When not emulating the Unix behavior of chroot, + allow a null root to delete the root path. */ + if (path == NULL || *path == '\0') + { + if (unix_emu) + { + errno = ENOENT; + return -1; + } + __djgpp_root[0] = '\0'; + __djgpp_root_len = 0; + setenv(ROOT_ENV, __djgpp_root, 1); + return 0; + } + + /* When in Unix/restrictive mode, don't allow drive letters + in a new root directory after a root directory has been set. + Even if the new directory is relative to the root. */ + if (*path && *(path+1) == ':') + { + if (unix_emu && __djgpp_root_len > 0) + { + errno = EACCES; + return -1; + } + _fixpath(path, buf); + } + else if (*path != '/' && *path != '\\' && __djgpp_root_len > 0) + { + /* Relative paths are relative to the root, not the cwd. */ + char path_buf[PATH_MAX+1]; + path_buf[0] = '/'; + strcpy(path_buf+1, path); + _fixpath(path_buf, buf); + } + else + _fixpath(path, buf); + + if (unix_emu) + { + /* If a root directory already exists, the new root directory + must be relative to the existing root directory. + If not, then reject the path. */ + if (__djgpp_root_len > 0 && *buf != '/') + { + errno = EACCES; + return -1; + } + } + + /* Make sure the path is valid before + making it the new root path. */ + if (access(buf, D_OK) < 0) + return -1; + + /* Copy in the new root path. */ + if (*buf != '/') + __djgpp_root_len = 0; + else /* Append to the current root path. */ + to = __djgpp_root + __djgpp_root_len; + + while (*from) + { + *to = *from; + ++to; + ++from; + ++__djgpp_root_len; + } + + /* Set up environmental variables to be used so child programs + created with DJGPP will inherit the root path and mode. */ + setenv(ROOT_ENV, __djgpp_root, 1); + + if (old_flags != __chroot_flags) + { + setenv(CHROOT_ENV, (unix_emu ? "Y" : "N"), 1); + old_flags = __chroot_flags; + } + + return 0; + } + + + /* Delete the root path from an input path. + The input path is assumed to have already been canonicalized. */ + + char * + __delete_root (char *path) + { + if (__djgpp_root_len > 0 && path[0] != '/') + { + if (strnicmp (path, __djgpp_root, __djgpp_root_len) == 0 + && (path[__djgpp_root_len] == '/' || path[__djgpp_root_len] == '\0')) + { + if (path[__djgpp_root_len] == '/') + strcpy (path, path + __djgpp_root_len); + else + { + /* path is equal to the root path. */ + path[0] = '/'; + path[1] = '\0'; + } + } + } + return path; + } + *** src/libc/compat/unistd/fchroot.c.orig Sun Feb 28 14:25:24 1999 --- src/libc/compat/unistd/fchroot.c Wed Mar 3 17:34:36 1999 *************** *** 0 **** --- 1,17 ---- + #include + #include + #include + + int + fchroot (int fd) + { + unsigned int flags = __chroot_flags; + + /* Use &= in case more flags are ever added. */ + __chroot_flags &= ~__CHROOT_UNIX_MODE_FLAG; + chroot (NULL); + __chroot_flags = flags; + + return 0; + } + *** src/libc/dos/io/putpath.c.orig Thu Oct 29 05:24:44 1998 --- src/libc/dos/io/putpath.c Thu Feb 25 14:02:32 1999 *************** *** 3,8 **** --- 3,9 ---- #include #include #include + #include #include #include #include *************** *** 49,54 **** --- 50,66 ---- } else if (p[5]) path = p + 5; + } + /* If the path is absolute and a root path is set, + then add the root path to the output. */ + else if (path[0] == '/' && __djgpp_root_len > 0 ) + { + char *root = __djgpp_root; + for ( ; *root; root++) + { + _farnspokeb (o++, *root); + space -= 1; + } } /* collapse multiple slashes to a single slash */ *** src/libc/posix/sys/stat/fixpath.c.orig Sun Dec 13 08:09:46 1998 --- src/libc/posix/sys/stat/fixpath.c Thu Feb 25 14:01:42 1999 *************** *** 13,18 **** --- 13,19 ---- #include /* For crt0 flags */ #include #include + #include static unsigned use_lfn; *************** *** 73,78 **** --- 74,80 ---- 5. Removing ".." entries in the path (and the directory above them) 6. Adding a drive specification if one wasn't there 7. Converting all slashes to '/' + 8. Remove the portion of the path matching the root path */ void _fixpath(const char *in, char *out) *************** *** 227,232 **** --- 229,240 ---- } else if (*op == '\0') break; + } + + /* Remove the portion of the path matching the root path */ + if (__djgpp_root_len > 0 && out[0] != '/') + { + __delete_root(out); } } *** src/libc/compat/unistd/chroot.txh.orig Sun Feb 28 14:25:02 1999 --- src/libc/compat/unistd/chroot.txh Thu Mar 4 12:31:42 1999 *************** *** 0 **** --- 1,104 ---- + @node chroot, file system + @subheading Syntax + + @example + #include + + extern unsigned int __chroot_flags; + + int chroot(const char *new_root_directory); + @end example + + @subheading Description + + Causes @var{new_root_directory} to become the root directory, or + starting point, for path name searches beginning with @file{/} or + @file{\}. The current working directory is unaffected. + + By default, @code{chroot} is set to Unix compatibility or restrictive + mode. In this mode, @var{new_root_directory} can be any existing + directory. In successive calls, @var{new_root_directory} must exist and + be relative to the current root directory, or else the call fails. The + only way to reset the root directory is with a call to @code{fchroot} + (@pxref{fchroot}). This mimics the behavior of Unix versions of + @code{chroot}. + + The other available mode is Bash compatibility or permissive mode. In + this mode, @var{new_root_directory} must still exist, but it need not be + relative to the current root like in restrictive mode. This mimics the + behavior of the @code{SYSROOT} environment variable in the DJGPP port of + Bash 1.14.7. + + To allow a child program to inherit the root directory of its parent, + @code{chroot} sets the environment variables @code{ROOT} and + @code{CHROOT_UNIX}. If set, @code{ROOT} will contain the root + directory. If @var{CHROOT_UNIX} is not set or is set to @samp{Y}, + @code{chroot} is set to enforce the restrictive Unix behavior. If + @code{CHROOT_UNIX} is set to anything other than @samp{Y}, then + @code{chroot} is set to allow the permissive behavior. @code{SYSROOT}, + an environment variable used by the DJGPP port of Bash 1.14.7, is + supported in the interest of backward compatibility but its use is + discouraged. If @code{ROOT} is not set, but @code{SYSROOT} is, then + @code{SYSROOT} is used to set the root directory, and @code{chroot} is + set to permissive mode, and @code{CHROOT_UNIX} is ignored. + + The global variable @code{__chroot_flags} can be set to include the + following values to control the operation of @code{chroot}: + + @table @code + + @item __CHROOT_UNIX_MODE_FLAG + + If set, @code{chroot} is in Unix compatibility or restrictive mode. If + not set, @code{chroot} is in Bash compatibility or permissive mode. See + the above description for how these two modes differ. + + @end table + + @subheading Return Value + + Zero if successful, else nonzero and @code{errno} set if error. + + @subheading Portability + + @port-note The variable @code{__chroot_flags} is DJGPP specific. + @portability !ansi, !posix + + @subheading Example + + In our examples, assume 'c:/djgpp' and 'c:/djgpp/bin/gcc.exe' exist. + + An example for Unix compatibility or restrictive mode: + + @example + chroot("c:/djgpp"); + + /* This call will not succeed. Root will not be changed. */ + chroot("c:/"); + + /* Checks c:/djgpp/bin/gcc.exe */ + if (access("/bin/gcc.exe", R_OK) == 0) + printf("gcc.exe found"); + + /* Succeeds because 'c:/djgpp/bin' is relative to 'c:/djgpp'. + Passing in '/bin' would have also worked. */ + chroot("c:/djgpp/bin"); + @end example + + An example for Bash compatibility or permissive mode: + + @example + /* Disable Unix compatibility or restrictive mode. */ + __chroot_flags = 0; + + chroot("c:/djgpp"); + + /* This will succeed since directory need not be relative + to 'c:/djgpp' like in the first example. */ + chroot("c:/"); + + /* You can change to any directory on any drive as long + as the directory exists. */ + chroot("d:/windows"); + @end example + *** src/libc/compat/unistd/fchroot.txh.orig Sun Feb 28 14:24:58 1999 --- src/libc/compat/unistd/fchroot.txh Thu Mar 4 12:30:24 1999 *************** *** 0 **** --- 1,39 ---- + @node fchroot, file system + @subheading Syntax + + @example + #include + + int fchroot(int file_handle); + @end example + + @subheading Description + + Clears the root directory set by any previous calls to @xref{chroot}. + Because DOS does not allow you to obtain a file handle to a + directory, @var{file_handle} is ignored. This does introduce an + incompatibility with Unix. However, since @code{fchroot} in Unix + is guaranteed to succeed only when changing to the system root, + this function will be portable most of the time. + + @subheading Return Value + + Always returns zero for success, unless @var{file_handle} is less than + zero. + + @subheading Portability + + @portability !ansi, !posix + + @subheading Example + + @example + chroot("c:/djgpp"); + if (access("/bin/gcc.exe", R_OK) < 0) + fprintf(stderr, "gcc.exe not found"); + + fchroot(1); + + if (access("/bin/gcc.exe", R_OK) < 0) + fprintf(stderr, "gcc.exe not found"); + @end example *** src/libc/posix/unistd/getcwd.c.orig Sat Aug 31 18:09:32 1996 --- src/libc/posix/unistd/getcwd.c Sun Feb 28 14:41:40 1999 *************** *** 13,18 **** --- 13,19 ---- #include #include #include + #include char * __getcwd(char *buf, size_t size) *************** *** 107,112 **** --- 108,119 ---- __dpmi_int(0x21, &r); buf[0] = r.h.al + (r.h.al < 26 ? 'a' : 'A'); + + /* See if we need to strip the root path set by chroot */ + if (__djgpp_root_len > '\0') + { + __delete_root(buf); + } return buf; } *** src/libc/crt0/crt1.c.orig Thu Sep 17 05:50:22 1998 --- src/libc/crt0/crt1.c Fri Feb 26 17:51:42 1999 *************** *** 1,3 **** --- 1,4 ---- + /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ *************** *** 189,194 **** --- 190,196 ---- __crt0_setup_arguments(); _npxsetup(__crt0_argv ? __crt0_argv[0] : __dos_argv0); _crt0_init_mcount(); + __crt0_setup_chroot(); __main(); errno = 0; /* ANSI says errno should be zero at program startup */ exit(main(__crt0_argc, __crt0_argv, environ)); *** src/libc/crt0/c1root.c.orig Sun Feb 28 14:08:22 1999 --- src/libc/crt0/c1root.c Thu Mar 4 12:46:52 1999 *************** *** 0 **** --- 1,69 ---- + #include + #include + #include + #include + #include + + /* Here is we check for three environmental variables + that may result in a call to chroot(): + ROOT - the root path. Can be set manually or by chroot(). + CHROOT_UNIX - Y if chroot is to emulate the restrictive + behavior of the Unix implementations. + Any other value to select the non-restrictive + behavior implemented by Bash 1.147. + SYSROOT - Bash 1.147 sets this variable to the directory to + use when searching for path names beginning + with '/' or '\'. If ROOT is set, this variable + is ignored. If ROOT is not set and SYSROOT does + contain a path, then chroot() emulates the + non-restrictive behavior of Bash 1.147 regardless + of the value of CHROOT_UNIX. This variable is checked + to maintain backward compatibility with Bash 1.147. + Someday, this variable will be completely ignored + once a DJGPP port of Bash 2 has been released + and is in wide use. */ + + + static int __setup_root_bss_count = 0; + + void + __crt0_setup_chroot() + { + char *root = getenv(ROOT_ENV); + char *sysroot = (root ? NULL : getenv("SYSROOT")); + char *unix_mode = (!sysroot ? getenv(CHROOT_ENV) : NULL); + int ret_code; + + if (unix_mode) + { + if (*unix_mode == 'Y' || *unix_mode == 'y') + __chroot_flags = __CHROOT_UNIX_MODE_FLAG; + else + __chroot_flags = 0; + } + else if (sysroot) + __chroot_flags = 0; + + if (sysroot) + root = sysroot; + + if (root) + { + __setup_root_bss_count = __bss_count; + /* Aborts if call to chroot() fails. */ + if (chroot(root) < 0) + { + fprintf(stderr, "Call to chroot('%s') failed in __crt0_setup_chroot()\n", root); + abort(); + } + } + /* If restarting, and ROOT or SYSROOT was not defined, + then reset _djgpp_root to no root. */ + else if (__setup_root_bss_count != __bss_count) + { + __djgpp_root[0] = '\0'; + __djgpp_root_len = 0; + __setup_root_bss_count = __bss_count; + } + } + --- Mark Elbrecht snowball3 AT usa DOT net http://members.xoom.com/snowball3/