diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 3dff4fa30..d6cf41ca8 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,20 @@ +Wed Jul 19 22:11:00 2000 Corinna Vinschen + + * shared.h (class pinfo): New members `root' and `rootlen'. + * syscalls.cc (chroot): Set new root for process. + * path.cc (getcwd_inner): Add parameter to force use of + new root from chroot() call. + (ischrootpath): New macro. + (normalize_posix_path): Care for changed root dir. + (normalize_win32_path): Ditto. + (getcwd_inner): Ditto. + (chdir): Eliminate trailing path component consisting + entirely of dots. + * fork.cc (fork): Copy pinfo members regarding chroot(). + * spawn.cc (_spawnve): Ditto. + * dir.cc (opendir): Don't use computed win32 path if + chroot() took place. + Mon Jul 17 22:21:34 2000 Christopher Faylor * dll_init.cc (dll_list::alloc): Fix debugging output. diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 1b409060e..7323cb388 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -67,7 +67,8 @@ opendir (const char *dirname) goto failed; } - if (stat (real_dirname.get_win32 (), &statbuf) == -1) + if (stat (myself->rootlen ? dirname : real_dirname.get_win32 (), + &statbuf) == -1) goto failed; if (!(statbuf.st_mode & S_IFDIR)) diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index fdd63c6e3..e585fad36 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -437,6 +437,8 @@ fork () child->orig_gid = myself->orig_gid; child->real_uid = myself->real_uid; child->real_gid = myself->real_gid; + memcpy (child->root, myself->root, MAX_PATH+1); + child->rootlen = myself->rootlen; set_child_mmap_ptr (child); /* Wait for subproc to initialize itself. */ diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index fb50a4571..7995747bf 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -83,7 +83,7 @@ details. */ #include static int normalize_win32_path (const char *cwd, const char *src, char *dst); -static char *getcwd_inner (char *buf, size_t ulen, int posix_p); +static char *getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot); static void slashify (const char *src, char *dst, int trailing_slash_p); static void backslashify (const char *src, char *dst, int trailing_slash_p); static int path_prefix_p_ (const char *path1, const char *path2, int len1); @@ -152,6 +152,11 @@ static char *cwd_posix; static unsigned long cwd_hash; #endif +#define ischrootpath(path) \ + (myself->rootlen && \ + strncasematch (myself->root, path, myself->rootlen) && \ + (path[myself->rootlen] == '/' || path[myself->rootlen] == '\0')) + static int path_prefix_p_ (const char *path1, const char *path2, int len1) { @@ -584,6 +589,11 @@ normalize_posix_path (const char *cwd, const char *src, char *dst) /* Two leading /'s? If so, preserve them. */ else if (isslash (src[1])) { + if (myself->rootlen) + { + debug_printf ("ENOENT = normalize_posix_path (%s)", src); + return ENOENT; + } *dst++ = '/'; *dst++ = '/'; src += 2; @@ -594,6 +604,12 @@ normalize_posix_path (const char *cwd, const char *src, char *dst) src = src_start + 1; } } + /* Exactly one leading slash. Absolute path. Check for chroot. */ + else if (myself->rootlen) + { + strcpy (dst, myself->root); + dst += myself->rootlen; + } while (*src) { @@ -620,8 +636,10 @@ normalize_posix_path (const char *cwd, const char *src, char *dst) { if (src[2] && !isslash (src[2])) break; - while (dst > dst_start && !isslash (*--dst)) - continue; + if (!ischrootpath (dst_start) || + dst - dst_start != (int) myself->rootlen) + while (dst > dst_start && !isslash (*--dst)) + continue; src++; } } @@ -644,12 +662,12 @@ normalize_posix_path (const char *cwd, const char *src, char *dst) The result is 0 for success, or an errno error value. FIXME: A lot of this should be mergeable with the POSIX critter. */ - static int normalize_win32_path (const char *cwd, const char *src, char *dst) { const char *src_start = src; char *dst_start = dst; + char *dst_root_start = dst; if (!SLASH_P (src[0]) && strchr (src, ':') == NULL) { @@ -666,9 +684,25 @@ normalize_win32_path (const char *cwd, const char *src, char *dst) /* Two leading \'s? If so, preserve them. */ else if (SLASH_P (src[0]) && SLASH_P (src[1])) { + if (myself->rootlen) + { + debug_printf ("ENOENT = normalize_win32_path (%s)", src); + return ENOENT; + } *dst++ = '\\'; ++src; } + /* If absolute path, care for chroot. */ + else if (SLASH_P (src[0]) && !SLASH_P (src[1]) && myself->rootlen) + { + strcpy (dst, myself->root); + char *c; + while ((c = strchr (dst, '/')) != NULL) + *c = '\\'; + dst += myself->rootlen; + dst_root_start = dst; + *dst++ = '\\'; + } while (*src) { @@ -689,10 +723,10 @@ normalize_win32_path (const char *cwd, const char *src, char *dst) && (SLASH_P (src[2]) || src[2] == 0)) { /* Back up over /, but not if it's the first one. */ - if (dst > dst_start + 1) + if (dst > dst_root_start + 1) dst--; /* Now back up to the next /. */ - while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':') + while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':') dst--; src += 2; if (SLASH_P (*src)) @@ -908,7 +942,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *win32_path, char pathbuf[MAX_PATH]; char cwd[MAX_PATH]; - getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */ + getcwd_inner (cwd, MAX_PATH, TRUE, 0); /* FIXME: check rc */ /* Determine where the destination should be placed. */ if (full_win32_path != NULL) @@ -932,6 +966,22 @@ mount_info::conv_to_win32_path (const char *src_path, char *win32_path, } isrelpath = !isabspath (src_path); *flags = set_flags_from_win32_path (dst); + if (myself->rootlen && dst[0] && dst[1] == ':') + { + char posix_path[MAX_PATH + 1]; + + rc = cygwin_shared->mount.conv_to_posix_path (dst, posix_path, 0); + if (rc) + { + debug_printf ("conv_to_posix_path failed, rc %d", rc); + return rc; + } + if (!ischrootpath (posix_path)) + { + debug_printf ("ischrootpath failed"); + return ENOENT; + } + } goto fillin; } @@ -1161,7 +1211,7 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, /* No need to fetch cwd if path is absolute. */ if (relative_path_p) - getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */ + getcwd_inner (cwd, MAX_PATH, 0, 0); /* FIXME: check rc */ else strcpy (cwd, "/"); /* some innocuous value */ @@ -2345,7 +2395,7 @@ get_cwd_win32 () /* getcwd */ char * -getcwd_inner (char *buf, size_t ulen, int posix_p) +getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot) { char *resbuf = NULL; size_t len = ulen; @@ -2369,8 +2419,16 @@ getcwd_inner (char *buf, size_t ulen, int posix_p) } else if (cwd_posix != NULL) { + debug_printf("myself->root: %s, cwd_posix: %s", myself->root, cwd_posix); if (strlen (cwd_posix) >= len) set_errno (ERANGE); + else if (with_chroot && ischrootpath(cwd_posix)) + { + strcpy (buf, cwd_posix + myself->rootlen); + if (!buf[0]) + strcpy (buf, "/"); + resbuf = buf; + } else { strcpy (buf, cwd_posix); @@ -2391,10 +2449,20 @@ getcwd_inner (char *buf, size_t ulen, int posix_p) size_t tlen = strlen (temp); + if (with_chroot && ischrootpath (temp)) + tlen -= myself->rootlen; + cwd_posix = (char *) realloc ( cwd_posix, tlen + 1); if (cwd_posix != NULL) - strcpy (cwd_posix, temp); + if (with_chroot && ischrootpath (temp)) + { + strcpy (cwd_posix, temp + myself->rootlen); + if (!buf[0]) + strcpy (buf, "/"); + } + else + strcpy (cwd_posix, temp); if (tlen >= ulen) { @@ -2421,12 +2489,12 @@ getcwd (char *buf, size_t ulen) if (buf == NULL || ulen == 0) { buf = (char *) alloca (MAX_PATH); - res = getcwd_inner (buf, MAX_PATH, 1); + res = getcwd_inner (buf, MAX_PATH, 1, 1); res = strdup (buf); } else { - res = getcwd_inner (buf, ulen, 1); + res = getcwd_inner (buf, ulen, 1, 1); } return res; @@ -2477,6 +2545,13 @@ chdir (const char *dir) char pathbuf[MAX_PATH]; (void) normalize_posix_path (cwd_posix, dir, pathbuf); + /* Look for trailing path component consisting entirely of dots. This + is needed only in case of chdir since Windows simply ignores count + of dots > 2 here instead of returning an error code. Counts of dots + <= 2 are already eliminated by normalize_posix_path. */ + char *last_slash = strrchr (pathbuf, '/'); + if (last_slash && strspn (last_slash + 1, ".") == strlen (last_slash + 1)) + *last_slash = '\0'; free (cwd_posix); cwd_posix = strdup (pathbuf); } diff --git a/winsup/cygwin/shared.h b/winsup/cygwin/shared.h index 5c5ea8348..d6e465544 100644 --- a/winsup/cygwin/shared.h +++ b/winsup/cygwin/shared.h @@ -102,6 +102,11 @@ class pinfo uid_t real_uid; /* Remains intact on seteuid, replaced by setuid */ gid_t real_gid; /* Ditto */ + /* Filled when chroot() is called by the process or one of it's parents. + Saved without trailing backslash. */ + char root[MAX_PATH+1]; + size_t rootlen; + /* Non-zero if process was stopped by a signal. */ char stopsig; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 063e99ff3..4c1c72c52 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -852,6 +852,8 @@ _spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv, child->psid = child->sidbuf; memcpy (child->logsrv, myself->logsrv, MAX_HOST_NAME); memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + memcpy (child->root, myself->root, MAX_PATH+1); + child->rootlen = myself->rootlen; subproc_init (); ret = spawn_guts (hToken, path, argv, envp, child, mode); if (ret == -1) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index b237f8264..5935bdb41 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1917,12 +1917,42 @@ setegid (gid_t gid) } /* chroot: privileged Unix system call. */ +/* FIXME: Not privileged here. How should this be done? */ extern "C" int -chroot (const char *) +chroot (const char *newroot) { - set_errno (ENOSYS); - return -1; + int ret = -1; + path_conv path(newroot, PC_SYM_FOLLOW | PC_FULL); + + if (path.error) + goto done; + if (path.file_attributes () == (DWORD)-1) + { + set_errno (ENOENT); + goto done; + } + if (!(path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)) + { + set_errno (ENOTDIR); + goto done; + } + ret = cygwin_shared->mount.conv_to_posix_path (path.get_win32 (), + myself->root, 0); + if (ret) + { + set_errno (ret); + goto done; + } + myself->rootlen = strlen (myself->root); + if (myself->root[myself->rootlen - 1] == '/') + myself->root[--myself->rootlen] = '\0'; + ret = 0; + +done: + syscall_printf ("%d = chroot (%s)", ret ? get_errno () : 0, + newroot ? newroot : "NULL"); + return ret; } extern "C"