mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-09-26 11:29:04 +02:00
Enable SFTP chroot support (#308)
- Added chroot implementation that simply stores the path in internal state and sets an environment variable - Spawned processes pickup chroot from environment variable - Core change in realpath and resolved_path_utf16 now take into account chroot path. - Unit tests - Other miscellaneous changes to account for chroot enabled logic in core code PowerShell/Win32-OpenSSH#190 PowerShell/Win32-OpenSSH#292
This commit is contained in:
parent
936b89ac0d
commit
7b28a316eb
@ -96,6 +96,7 @@ errno_from_Win32Error(int win32_error)
|
||||
return EEXIST;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_NAME:
|
||||
return ENOENT;
|
||||
default:
|
||||
return win32_error;
|
||||
@ -421,14 +422,36 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* returns 1 if true, 0 otherwise */
|
||||
int
|
||||
file_in_chroot_jail(HANDLE handle, const char* path_utf8) {
|
||||
/* ensure final path is within chroot */
|
||||
wchar_t path_buf[MAX_PATH], *final_path;
|
||||
if (GetFinalPathNameByHandleW(handle, path_buf, MAX_PATH, 0) == 0) {
|
||||
debug3("failed to get final path of file:%s error:%d", path_utf8, GetLastError());
|
||||
return 0;
|
||||
}
|
||||
final_path = path_buf + 4;
|
||||
to_wlower_case(final_path);
|
||||
if ((wcslen(final_path) < wcslen(chroot_pathw)) ||
|
||||
memcmp(final_path, chroot_pathw, 2 * wcslen(chroot_pathw)) != 0 ||
|
||||
final_path[wcslen(chroot_pathw)] != '\\') {
|
||||
debug3("access denied due to attempt to escape chroot jail");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* open() implementation. Uses CreateFile to open file, console, device, etc */
|
||||
struct w32_io*
|
||||
fileio_open(const char *path_utf8, int flags, mode_t mode)
|
||||
{
|
||||
struct w32_io* pio = NULL;
|
||||
struct createFile_flags cf_flags;
|
||||
HANDLE handle;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
wchar_t *path_utf16 = NULL;
|
||||
int nonfs_dev = 0; /* opening a non file system device */
|
||||
|
||||
debug4("open - pathname:%s, flags:%d, mode:%d", path_utf8, flags, mode);
|
||||
/* check input params*/
|
||||
@ -439,14 +462,15 @@ fileio_open(const char *path_utf8, int flags, mode_t mode)
|
||||
}
|
||||
|
||||
/* if opening null device, point to Windows equivalent */
|
||||
if (strncmp(path_utf8, NULL_DEVICE, sizeof(NULL_DEVICE)) == 0)
|
||||
path_utf8 = NULL_DEVICE_WIN;
|
||||
|
||||
if ((path_utf16 = resolved_path_utf16(path_utf8)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
debug3("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError());
|
||||
return NULL;
|
||||
if (strncmp(path_utf8, NULL_DEVICE, sizeof(NULL_DEVICE)) == 0) {
|
||||
nonfs_dev = 1;
|
||||
path_utf16 = utf8_to_utf16(NULL_DEVICE_WIN);
|
||||
}
|
||||
else
|
||||
path_utf16 = resolved_path_utf16(path_utf8);
|
||||
|
||||
if (path_utf16 == NULL)
|
||||
return NULL;
|
||||
|
||||
if (createFile_flags_setup(flags, mode, &cf_flags) == -1) {
|
||||
debug3("createFile_flags_setup() failed.");
|
||||
@ -463,6 +487,10 @@ fileio_open(const char *path_utf8, int flags, mode_t mode)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (chroot_pathw && !nonfs_dev && !file_in_chroot_jail(handle, path_utf8)) {
|
||||
errno = EACCES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pio = (struct w32_io*)malloc(sizeof(struct w32_io));
|
||||
if (pio == NULL) {
|
||||
@ -478,11 +506,16 @@ fileio_open(const char *path_utf8, int flags, mode_t mode)
|
||||
pio->fd_status_flags = O_NONBLOCK;
|
||||
|
||||
pio->handle = handle;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
cleanup:
|
||||
if ((&cf_flags.securityAttributes != NULL) && (&cf_flags.securityAttributes.lpSecurityDescriptor != NULL))
|
||||
LocalFree(cf_flags.securityAttributes.lpSecurityDescriptor);
|
||||
if(path_utf16)
|
||||
free(path_utf16);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
|
||||
return pio;
|
||||
}
|
||||
|
||||
@ -774,11 +807,8 @@ fileio_stat_or_lstat_internal(const char *path, struct _stat64 *buf, int do_lsta
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((wpath = resolved_path_utf16(path)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
debug3("utf8_to_utf16 failed for file:%s error:%d", path, GetLastError());
|
||||
if ((wpath = resolved_path_utf16(path)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get the file attributes (or symlink attributes if symlink) */
|
||||
if (GetFileAttributesExW(wpath, GetFileExInfoStandard, &attributes) == FALSE) {
|
||||
@ -1039,10 +1069,8 @@ fileio_readlink(const char *path, char *buf, size_t bufsiz)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((wpath = resolved_path_utf16(path)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
if ((wpath = resolved_path_utf16(path)) == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* obtain a handle to send to deviceioctl */
|
||||
handle = CreateFileW(wpath, 0, 0, NULL, OPEN_EXISTING,
|
||||
@ -1123,18 +1151,21 @@ cleanup:
|
||||
int
|
||||
fileio_symlink(const char *target, const char *linkpath)
|
||||
{
|
||||
DWORD ret = -1;
|
||||
|
||||
if (target == NULL || linkpath == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD ret = 0;
|
||||
wchar_t *target_utf16 = resolved_path_utf16(target);
|
||||
wchar_t *linkpath_utf16 = resolved_path_utf16(linkpath);
|
||||
wchar_t *resolved_utf16 = _wcsdup(target_utf16);
|
||||
if (target_utf16 == NULL || linkpath_utf16 == NULL || resolved_utf16 == NULL) {
|
||||
if (target_utf16 == NULL || linkpath_utf16 == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (resolved_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -1151,7 +1182,6 @@ fileio_symlink(const char *target, const char *linkpath)
|
||||
resolved_utf16 = malloc(resolved_len * sizeof(wchar_t));
|
||||
if (resolved_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -1171,7 +1201,6 @@ fileio_symlink(const char *target, const char *linkpath)
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 };
|
||||
if (GetFileAttributesExW(resolved_utf16, GetFileExInfoStandard, &attributes) == FALSE) {
|
||||
errno = errno_from_Win32LastError();
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -1187,11 +1216,11 @@ fileio_symlink(const char *target, const char *linkpath)
|
||||
if (CreateSymbolicLinkW(linkpath_utf16, target_utf16, create_flags) == 0) {
|
||||
if (CreateSymbolicLinkW(linkpath_utf16, target_utf16, create_flags | 0x2) == 0) {
|
||||
errno = errno_from_Win32LastError();
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
|
||||
if (target_utf16)
|
||||
@ -1206,28 +1235,25 @@ cleanup:
|
||||
int
|
||||
fileio_link(const char *oldpath, const char *newpath)
|
||||
{
|
||||
DWORD ret = -1;
|
||||
|
||||
if (oldpath == NULL || newpath == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD ret = 0;
|
||||
|
||||
wchar_t *oldpath_utf16 = resolved_path_utf16(oldpath);
|
||||
wchar_t *newpath_utf16 = resolved_path_utf16(newpath);
|
||||
|
||||
if (oldpath_utf16 == NULL || newpath_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
if (oldpath_utf16 == NULL || newpath_utf16 == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (CreateHardLinkW(newpath_utf16, oldpath_utf16, NULL) == 0) {
|
||||
errno = errno_from_Win32LastError();
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
|
||||
if (oldpath_utf16)
|
||||
|
@ -19,8 +19,8 @@ struct dirent {
|
||||
|
||||
typedef struct DIR_ DIR;
|
||||
|
||||
DIR * opendir(const char *name);
|
||||
int closedir(DIR *dirp);
|
||||
struct dirent *readdir(void *avp);
|
||||
DIR * opendir(const char*);
|
||||
int closedir(DIR*);
|
||||
struct dirent *readdir(void*);
|
||||
|
||||
#endif
|
@ -132,6 +132,12 @@ char* _sys_errlist_ext[] = {
|
||||
"Operation would block" /* EWOULDBLOCK 140 */
|
||||
};
|
||||
|
||||
/* chroot state */
|
||||
char* chroot_path = NULL;
|
||||
int chroot_path_len = 0;
|
||||
/* UTF-16 version of the above */
|
||||
wchar_t* chroot_pathw = NULL;
|
||||
|
||||
int
|
||||
usleep(unsigned int useconds)
|
||||
{
|
||||
@ -247,6 +253,7 @@ w32_fopen_utf8(const char *input_path, const char *mode)
|
||||
char first3_bytes[3];
|
||||
int status = 1;
|
||||
errno_t r = 0;
|
||||
int nonfs_dev = 0; /* opening a non file system device */
|
||||
|
||||
if (mode == NULL || mode[1] != '\0') {
|
||||
errno = ENOTSUP;
|
||||
@ -260,21 +267,32 @@ w32_fopen_utf8(const char *input_path, const char *mode)
|
||||
}
|
||||
|
||||
/* if opening null device, point to Windows equivalent */
|
||||
if (strncmp(input_path, NULL_DEVICE, sizeof(NULL_DEVICE)) == 0)
|
||||
input_path = NULL_DEVICE_WIN;
|
||||
|
||||
wpath = resolved_path_utf16(input_path);
|
||||
if (strncmp(input_path, NULL_DEVICE, sizeof(NULL_DEVICE)) == 0) {
|
||||
nonfs_dev = 1;
|
||||
wpath = utf8_to_utf16(NULL_DEVICE_WIN);
|
||||
}
|
||||
else
|
||||
wpath = resolved_path_utf16(input_path);
|
||||
|
||||
wmode = utf8_to_utf16(mode);
|
||||
if (wpath == NULL || wmode == NULL)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((_wfopen_s(&f, wpath, wmode) != 0) || (f == NULL)) {
|
||||
debug3("Failed to open file:%s error:%d", input_path, errno);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (chroot_pathw && !nonfs_dev) {
|
||||
/* ensure final path is within chroot */
|
||||
HANDLE h = (HANDLE)_get_osfhandle(_fileno(f));
|
||||
if (!file_in_chroot_jail(h, input_path)) {
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
errno = EACCES;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* BOM adjustments for file streams*/
|
||||
if (mode[0] == 'w' && fseek(f, 0, SEEK_SET) != EBADF) {
|
||||
@ -523,10 +541,9 @@ w32_chmod(const char *pathname, mode_t mode)
|
||||
{
|
||||
int ret;
|
||||
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(pathname);
|
||||
if (resolvedPathName_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
if (resolvedPathName_utf16 == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _wchmod(resolvedPathName_utf16, mode);
|
||||
free(resolvedPathName_utf16);
|
||||
return ret;
|
||||
@ -651,10 +668,9 @@ w32_utimes(const char *filename, struct timeval *tvp)
|
||||
int ret;
|
||||
FILETIME acttime, modtime;
|
||||
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(filename);
|
||||
if (resolvedPathName_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
if (resolvedPathName_utf16 == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&acttime, 0, sizeof(FILETIME));
|
||||
memset(&modtime, 0, sizeof(FILETIME));
|
||||
|
||||
@ -688,11 +704,9 @@ w32_rename(const char *old_name, const char *new_name)
|
||||
wchar_t *resolvedOldPathName_utf16 = resolved_path_utf16(old_name);
|
||||
wchar_t *resolvedNewPathName_utf16 = resolved_path_utf16(new_name);
|
||||
|
||||
if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* To be consistent with POSIX rename(),
|
||||
* 1) if the new_name is file, then delete it so that _wrename will succeed.
|
||||
@ -725,10 +739,8 @@ int
|
||||
w32_unlink(const char *path)
|
||||
{
|
||||
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(path);
|
||||
if (NULL == resolvedPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
if (NULL == resolvedPathName_utf16)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int returnStatus = _wunlink(resolvedPathName_utf16);
|
||||
free(resolvedPathName_utf16);
|
||||
@ -740,10 +752,8 @@ int
|
||||
w32_rmdir(const char *path)
|
||||
{
|
||||
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(path);
|
||||
if (NULL == resolvedPathName_utf16) {
|
||||
errno = ENOMEM;
|
||||
if (NULL == resolvedPathName_utf16)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int returnStatus = _wrmdir(resolvedPathName_utf16);
|
||||
free(resolvedPathName_utf16);
|
||||
@ -754,11 +764,9 @@ w32_rmdir(const char *path)
|
||||
int
|
||||
w32_chdir(const char *dirname_utf8)
|
||||
{
|
||||
wchar_t *dirname_utf16 = utf8_to_utf16(dirname_utf8);
|
||||
if (dirname_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
wchar_t *dirname_utf16 = resolved_path_utf16(dirname_utf8);
|
||||
if (dirname_utf16 == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int returnStatus = _wchdir(dirname_utf16);
|
||||
free(dirname_utf16);
|
||||
@ -792,6 +800,30 @@ w32_getcwd(char *buffer, int maxlen)
|
||||
return NULL;
|
||||
free(putf8);
|
||||
|
||||
to_lower_case(buffer);
|
||||
|
||||
if (chroot_path) {
|
||||
/* ensure we are within chroot jail */
|
||||
char c = buffer[chroot_path_len];
|
||||
if ( strlen(buffer) < chroot_path_len ||
|
||||
memcmp(chroot_path, buffer, chroot_path_len) != 0 ||
|
||||
(c != '\0' && c!= '\\') ) {
|
||||
errno = EOTHER;
|
||||
error("cwb is not currently within chroot");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* is cwd chroot ?*/
|
||||
if (c == '\0') {
|
||||
buffer[0] = '\\';
|
||||
buffer[1] = '\0';
|
||||
}
|
||||
else {
|
||||
char *tail = buffer + chroot_path_len;
|
||||
memmove_s(buffer, maxlen, tail, strlen(tail) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -800,10 +832,9 @@ w32_mkdir(const char *path_utf8, unsigned short mode)
|
||||
{
|
||||
int curmask;
|
||||
wchar_t *path_utf16 = resolved_path_utf16(path_utf8);
|
||||
if (path_utf16 == NULL) {
|
||||
errno = ENOMEM;
|
||||
if (path_utf16 == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int returnStatus = _wmkdir(path_utf16);
|
||||
if (returnStatus < 0) {
|
||||
free(path_utf16);
|
||||
@ -878,25 +909,55 @@ convertToForwardslash(char *str)
|
||||
char *
|
||||
realpath(const char *path, char resolved[PATH_MAX])
|
||||
{
|
||||
errno_t r = 0;
|
||||
if (!path || !resolved) return NULL;
|
||||
|
||||
char tempPath[PATH_MAX];
|
||||
size_t path_len = strlen(path);
|
||||
resolved[0] = '\0';
|
||||
|
||||
if (path_len > PATH_MAX - 1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((path_len >= 2) && (path[0] == '/') && path[1] && (path[2] == ':')) {
|
||||
if((r = strncpy_s(resolved, PATH_MAX, path + 1, path_len)) != 0 ) /* skip the first '/' */ {
|
||||
debug3("memcpy_s failed with error: %d.", r);
|
||||
/* resolve root directory to the same */
|
||||
if (path_len == 1 && (path[0] == '/' || path[0] == '\\')) {
|
||||
resolved[0] = '/';
|
||||
resolved[1] = '\0';
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/* resolve this common case scenario to root */
|
||||
/* "cd .." from within a drive root */
|
||||
if (path_len == 6 && !chroot_path) {
|
||||
char *tmplate = "/x:/..";
|
||||
strcat(resolved, path);
|
||||
resolved[1] = 'x';
|
||||
if (strcmp(tmplate, resolved) == 0) {
|
||||
resolved[0] = '/';
|
||||
resolved[1] = '\0';
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
if (chroot_path) {
|
||||
resolved[0] = '\0';
|
||||
strcat(resolved, chroot_path);
|
||||
/* if path is relative, add cwd within chroot */
|
||||
if (path[0] != '/' && path[0] != '\\') {
|
||||
w32_getcwd(resolved + chroot_path_len, PATH_MAX - chroot_path_len);
|
||||
strcat(resolved, "/");
|
||||
}
|
||||
strcat(resolved, path);
|
||||
}
|
||||
else if ((path_len >= 2) && (path[0] == '/') && path[1] && (path[2] == ':')) {
|
||||
if((errno = strncpy_s(resolved, PATH_MAX, path + 1, path_len)) != 0 ) /* skip the first '/' */ {
|
||||
debug3("memcpy_s failed with error: %d.", errno);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(( r = strncpy_s(resolved, PATH_MAX, path, path_len + 1)) != 0) {
|
||||
debug3("memcpy_s failed with error: %d.", r);
|
||||
else if(( errno = strncpy_s(resolved, PATH_MAX, path, path_len + 1)) != 0) {
|
||||
debug3("memcpy_s failed with error: %d.", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -905,27 +966,78 @@ realpath(const char *path, char resolved[PATH_MAX])
|
||||
resolved[3] = '\0';
|
||||
}
|
||||
|
||||
if (_fullpath(tempPath, resolved, PATH_MAX) == NULL)
|
||||
return NULL;
|
||||
|
||||
convertToForwardslash(tempPath);
|
||||
|
||||
resolved[0] = '/'; /* will be our first slash in /x:/users/test1 format */
|
||||
if ((r = strncpy_s(resolved+1, PATH_MAX - 1, tempPath, sizeof(tempPath) - 1)) != 0) {
|
||||
debug3("memcpy_s failed with error: %d.", r);
|
||||
if (_fullpath(tempPath, resolved, PATH_MAX) == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return resolved;
|
||||
|
||||
if (chroot_path) {
|
||||
if (strlen(tempPath) < strlen(chroot_path)) {
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
}
|
||||
if (memcmp(chroot_path, tempPath, strlen(chroot_path)) != 0) {
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resolved[0] = '\0';
|
||||
|
||||
|
||||
if (strlen(tempPath) == strlen(chroot_path))
|
||||
/* realpath is the same as chroot_path */
|
||||
strcat(resolved, "\\");
|
||||
else
|
||||
strcat(resolved, tempPath + strlen(chroot_path));
|
||||
|
||||
if (resolved[0] != '\\') {
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
convertToForwardslash(resolved);
|
||||
return resolved;
|
||||
}
|
||||
else {
|
||||
convertToForwardslash(tempPath);
|
||||
resolved[0] = '/'; /* will be our first slash in /x:/users/test1 format */
|
||||
if ((errno = strncpy_s(resolved + 1, PATH_MAX - 1, tempPath, sizeof(tempPath) - 1)) != 0) {
|
||||
debug3("memcpy_s failed with error: %d.", errno);
|
||||
return NULL;
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
/* on error returns NULL and sets errno */
|
||||
wchar_t*
|
||||
resolved_path_utf16(const char *input_path)
|
||||
{
|
||||
if (!input_path) return NULL;
|
||||
wchar_t *resolved_path = NULL;
|
||||
|
||||
wchar_t * resolved_path = utf8_to_utf16(input_path);
|
||||
if (resolved_path == NULL)
|
||||
if (!input_path) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (chroot_path) {
|
||||
char actual_path[MAX_PATH], jail_path[MAX_PATH];
|
||||
|
||||
if (realpath(input_path, jail_path) == NULL)
|
||||
return NULL;
|
||||
|
||||
actual_path[0] = '\0';
|
||||
strcat_s(actual_path, MAX_PATH, chroot_path);
|
||||
strcat_s(actual_path, MAX_PATH, jail_path);
|
||||
resolved_path = utf8_to_utf16(actual_path);
|
||||
}
|
||||
else
|
||||
resolved_path = utf8_to_utf16(input_path);
|
||||
|
||||
if (resolved_path == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int resolved_len = (int) wcslen(resolved_path);
|
||||
const int variable_len = (int) wcslen(PROGRAM_DATAW);
|
||||
@ -941,8 +1053,9 @@ resolved_path_utf16(const char *input_path)
|
||||
wchar_t * resolved_path_new = realloc(resolved_path,
|
||||
(resolved_len + changed_req + 1) * sizeof(wchar_t));
|
||||
if (resolved_path == NULL) {
|
||||
debug3("%s: memory allocation failed.", __FUNCTION__);
|
||||
free(resolved_path);
|
||||
debug3("%s: memory allocation failed.", __FUNCTION__);
|
||||
free(resolved_path);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
else resolved_path = resolved_path_new;
|
||||
@ -979,8 +1092,11 @@ statvfs(const char *path, struct statvfs *buf)
|
||||
DWORD totalClusters;
|
||||
|
||||
wchar_t* path_utf16 = resolved_path_utf16(path);
|
||||
if (path_utf16 && (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector,
|
||||
&freeClusters, &totalClusters) == TRUE)) {
|
||||
if (path_utf16 == NULL)
|
||||
return -1;
|
||||
|
||||
if (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector,
|
||||
&freeClusters, &totalClusters)) {
|
||||
debug5("path : [%s]", path);
|
||||
debug5("sectorsPerCluster : [%lu]", sectorsPerCluster);
|
||||
debug5("bytesPerSector : [%lu]", bytesPerSector);
|
||||
@ -1004,7 +1120,7 @@ statvfs(const char *path, struct statvfs *buf)
|
||||
return 0;
|
||||
} else {
|
||||
debug5("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", path, GetLastError());
|
||||
|
||||
errno = errno_from_Win32LastError();
|
||||
free(path_utf16);
|
||||
return -1;
|
||||
}
|
||||
@ -1271,6 +1387,13 @@ to_lower_case(char *s)
|
||||
*s = tolower((u_char)*s);
|
||||
}
|
||||
|
||||
void
|
||||
to_wlower_case(wchar_t *s)
|
||||
{
|
||||
for (; *s; s++)
|
||||
*s = towlower(*s);
|
||||
}
|
||||
|
||||
static int
|
||||
get_final_mode(int allow_mode, int deny_mode)
|
||||
{
|
||||
@ -1471,3 +1594,46 @@ localtime_r(const time_t *timep, struct tm *result)
|
||||
memcpy(result, t, sizeof(struct tm));
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
chroot(const char *path)
|
||||
{
|
||||
char cwd[MAX_PATH];
|
||||
|
||||
if (strcmp(path, ".") == 0) {
|
||||
if (w32_getcwd(cwd, MAX_PATH) == NULL)
|
||||
return -1;
|
||||
path = (const char *)cwd;
|
||||
} else if (*(path + 1) != ':') {
|
||||
errno = ENOTSUP;
|
||||
error("chroot only supports absolute paths");
|
||||
return -1;
|
||||
} else {
|
||||
/* TODO - ensure path exists and is a directory */
|
||||
}
|
||||
|
||||
if ((chroot_path = _strdup(path)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
to_lower_case(chroot_path);
|
||||
convertToBackslash(chroot_path);
|
||||
|
||||
/* strip trailing \ */
|
||||
if (chroot_path[strlen(chroot_path) - 1] == '\\')
|
||||
chroot_path[strlen(chroot_path) - 1] = '\0';
|
||||
|
||||
chroot_path_len = strlen(chroot_path);
|
||||
|
||||
if ((chroot_pathw = utf8_to_utf16(chroot_path)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO - set the env variable just in time in a posix_spawn_chroot like API */
|
||||
#define POSIX_CHROOTW L"c28fc6f98a2c44abbbd89d6a3037d0d9_POSIX_CHROOT"
|
||||
_wputenv_s(POSIX_CHROOTW, chroot_pathw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,6 +27,10 @@
|
||||
|
||||
static char *machine_domain_name;
|
||||
|
||||
extern char* chroot_path;
|
||||
extern int chroot_path_len;
|
||||
extern wchar_t* chroot_pathw;
|
||||
|
||||
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */
|
||||
wchar_t * resolved_path_utf16(const char *);
|
||||
void w32posix_initialize();
|
||||
@ -41,8 +45,10 @@ void file_time_to_unix_time(const LPFILETIME, time_t *);
|
||||
int file_attr_to_st_mode(wchar_t * path, DWORD attributes);
|
||||
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
|
||||
void to_lower_case(char *s);
|
||||
void to_wlower_case(wchar_t *s);
|
||||
wchar_t* get_program_data_path();
|
||||
HANDLE get_user_token(char* user, int impersonation);
|
||||
int load_user_profile(HANDLE user_token, char* user);
|
||||
int create_directory_withsddl(wchar_t *path, wchar_t *sddl);
|
||||
int is_absolute_path(const char *);
|
||||
int is_absolute_path(const char *);
|
||||
int file_in_chroot_jail(HANDLE, const char*);
|
@ -90,19 +90,14 @@ innetgr(const char *netgroup, const char *host, const char *user, const char *do
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* sshd.c */
|
||||
int
|
||||
chroot(const char *path)
|
||||
initgroups(const char *user, gid_t group)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
initgroups(const char *user, gid_t group)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sshd.c */
|
||||
int
|
||||
setgroups(gid_t group, char* name)
|
||||
{
|
||||
|
@ -260,7 +260,7 @@ user_from_uid(uid_t uid, int nouser)
|
||||
uid_t
|
||||
getuid(void)
|
||||
{
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
gid_t
|
||||
@ -272,7 +272,7 @@ getgid(void)
|
||||
uid_t
|
||||
geteuid(void)
|
||||
{
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
gid_t
|
||||
|
@ -318,6 +318,11 @@ STARTUPINFO inputSi;
|
||||
goto cleanup; \
|
||||
} while(0)
|
||||
|
||||
void
|
||||
debug3(const char *s, ...) {
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
ConSRWidth()
|
||||
{
|
||||
|
@ -30,7 +30,9 @@
|
||||
|
||||
#include <Windows.h>
|
||||
#include "inc\utf.h"
|
||||
#include "Debug.h"
|
||||
|
||||
/*on error returns NULL and sets errno*/
|
||||
wchar_t *
|
||||
utf8_to_utf16(const char *utf8)
|
||||
{
|
||||
@ -38,8 +40,11 @@ utf8_to_utf16(const char *utf8)
|
||||
wchar_t* utf16 = NULL;
|
||||
if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 ||
|
||||
(utf16 = malloc(needed * sizeof(wchar_t))) == NULL ||
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0)
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) {
|
||||
debug3("failed to convert utf8 payload:%s error:%d", utf8, GetLastError());
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return utf16;
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
||||
|
||||
if ((path_utf16 = resolved_path_utf16(input_path)) == NULL) {
|
||||
ret = -1;
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,8 @@ HANDLE main_thread;
|
||||
void fd_table_set(struct w32_io* pio, int index);
|
||||
|
||||
void fd_decode_state(char*);
|
||||
#define POSIX_STATE_ENV "c28fc6f98a2c44abbbd89d6a3037d0d9_POSIX_STATE"
|
||||
#define POSIX_FD_STATE "c28fc6f98a2c44abbbd89d6a3037d0d9_POSIX_FD_STATE"
|
||||
#define POSIX_CHROOTW L"c28fc6f98a2c44abbbd89d6a3037d0d9_POSIX_CHROOT"
|
||||
|
||||
/* __progname */
|
||||
char* __progname = "";
|
||||
@ -76,7 +77,6 @@ char* __progname = "";
|
||||
static int
|
||||
fd_table_initialize()
|
||||
{
|
||||
char *posix_state;
|
||||
struct w32_io *pio;
|
||||
HANDLE wh;
|
||||
/* table entries representing std in, out and error*/
|
||||
@ -101,17 +101,33 @@ fd_table_initialize()
|
||||
}
|
||||
}
|
||||
|
||||
_dupenv_s(&posix_state, NULL, POSIX_STATE_ENV);
|
||||
/*TODO - validate parent process - to accomodate these scenarios -
|
||||
* A posix parent process launches a regular process that inturn launches a posix child process
|
||||
* In this case the posix child process may misinterpret POSIX_STATE_ENV set by grand parent
|
||||
*/
|
||||
|
||||
if (NULL != posix_state) {
|
||||
fd_decode_state(posix_state);
|
||||
free(posix_state);
|
||||
_putenv_s(POSIX_STATE_ENV, "");
|
||||
/* decode fd state if any */
|
||||
{
|
||||
char *posix_fd_state;
|
||||
_dupenv_s(&posix_fd_state, NULL, POSIX_FD_STATE);
|
||||
/*TODO - validate parent process - to accomodate these scenarios -
|
||||
* A posix parent process launches a regular process that inturn launches a posix child process
|
||||
* In this case the posix child process may misinterpret POSIX_FD_STATE set by grand parent
|
||||
*/
|
||||
|
||||
if (NULL != posix_fd_state) {
|
||||
fd_decode_state(posix_fd_state);
|
||||
free(posix_fd_state);
|
||||
_putenv_s(POSIX_FD_STATE, "");
|
||||
}
|
||||
}
|
||||
|
||||
/* decode chroot if any */
|
||||
{
|
||||
_wdupenv_s(&chroot_pathw, NULL, POSIX_CHROOTW);
|
||||
if (chroot_pathw != NULL) {
|
||||
if ((chroot_path = utf16_to_utf8(chroot_pathw)) == NULL)
|
||||
return -1;
|
||||
chroot_path_len = strlen(chroot_path);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1235,7 +1251,7 @@ posix_spawn_internal(pid_t *pidp, const char *path, const posix_spawn_file_actio
|
||||
if ((fd_info = fd_encode_state(file_actions, aux_handles)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (_putenv_s(POSIX_STATE_ENV, fd_info) != 0)
|
||||
if (_putenv_s(POSIX_FD_STATE, fd_info) != 0)
|
||||
goto cleanup;
|
||||
i = spawn_child_internal(argv[0], argv + 1, stdio_handles[STDIN_FILENO], stdio_handles[STDOUT_FILENO], stdio_handles[STDERR_FILENO], sc_flags, user_token);
|
||||
if (i == -1)
|
||||
@ -1244,7 +1260,7 @@ posix_spawn_internal(pid_t *pidp, const char *path, const posix_spawn_file_actio
|
||||
*pidp = i;
|
||||
ret = 0;
|
||||
cleanup:
|
||||
_putenv_s(POSIX_STATE_ENV, "");
|
||||
_putenv_s(POSIX_FD_STATE, "");
|
||||
for (i = 0; i <= STDERR_FILENO; i++) {
|
||||
if (stdio_handles[i] != NULL) {
|
||||
if (fd_table.w32_ios[file_actions->stdio_redirect[i]]->type == SOCK_FD)
|
||||
|
@ -47,10 +47,10 @@ struct DIR_ {
|
||||
|
||||
#define ATTR_ROOTDIR UINT_MAX
|
||||
|
||||
/* Enumerate all devices which have drive name.
|
||||
Return a DIR stream on the root directory, or NULL if it could not be enumerated. */
|
||||
/* Enumerate all devices which have drive name.
|
||||
Return a DIR stream on the root directory, or NULL if it could not be enumerated. */
|
||||
DIR *
|
||||
openrootdir(const char *name)
|
||||
openrootdir()
|
||||
{
|
||||
int hr = 0;
|
||||
DWORD dw;
|
||||
@ -104,14 +104,12 @@ opendir(const char *name)
|
||||
wchar_t* wname = NULL;
|
||||
size_t len;
|
||||
|
||||
/* Detect root dir */
|
||||
if (name && strcmp(name, "/") == 0)
|
||||
return openrootdir(name);
|
||||
|
||||
if ((wname = resolved_path_utf16(name)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
if ((wname = resolved_path_utf16(name)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Detect root dir */
|
||||
if (wcscmp(wname, L"/") == 0)
|
||||
return openrootdir();
|
||||
|
||||
convertToBackslashW(wname);
|
||||
len = wcslen(wname);
|
||||
|
@ -82,7 +82,7 @@ platform_post_fork_child(void)
|
||||
int
|
||||
platform_privileged_uidswap(void)
|
||||
{
|
||||
#ifdef HAVE_CYGWIN
|
||||
#if defined(HAVE_CYGWIN) || defined(WINDOWS)
|
||||
/* uid 0 is not special on Cygwin so always try */
|
||||
return 1;
|
||||
#else
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "includes.h"
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <misc_internal.h>
|
||||
@ -68,6 +68,7 @@ test_sanitizedpath()
|
||||
ASSERT_PTR_NE(win32prgdir_utf8, NULL);
|
||||
|
||||
ASSERT_PTR_EQ(resolved_path_utf16(NULL), NULL);
|
||||
ASSERT_INT_EQ(errno, EINVAL);
|
||||
|
||||
wchar_t *win32prgdir = utf8_to_utf16(win32prgdir_utf8);
|
||||
wchar_t *ret = resolved_path_utf16(win32prgdir_utf8);
|
||||
@ -187,9 +188,129 @@ void test_realpath()
|
||||
ret = realpath("/c:", resolved_path);
|
||||
ASSERT_STRING_EQ(ret, expectedOutput2);
|
||||
|
||||
ASSERT_PTR_NE(ret = realpath("/c:/..", resolved_path), NULL);
|
||||
ASSERT_STRING_EQ(ret, "/");
|
||||
|
||||
ASSERT_PTR_NE(ret = realpath("/", resolved_path), NULL);
|
||||
ASSERT_STRING_EQ(ret, "/");
|
||||
|
||||
ASSERT_PTR_NE(ret = realpath("\\", resolved_path), NULL);
|
||||
ASSERT_STRING_EQ(ret, "/");
|
||||
|
||||
|
||||
TEST_DONE();
|
||||
}
|
||||
|
||||
void
|
||||
test_chroot()
|
||||
{
|
||||
int fd;
|
||||
FILE *f;
|
||||
char path[MAX_PATH], test_root[MAX_PATH];
|
||||
|
||||
/* test directory setup */
|
||||
_wsystem(L"RD /S /Q chroot-testdir >NUL 2>&1");
|
||||
CreateDirectoryW(L"chroot-testdir", NULL);
|
||||
CreateDirectoryW(L"chroot-testdir\\world", NULL);
|
||||
_wsystem(L"echo in-world > chroot-testdir\\world\\w.Txt");
|
||||
CreateDirectoryW(L"chroot-testdir\\jail", NULL);
|
||||
CreateDirectoryW(L"chroot-testdir\\jail\\d1", NULL);
|
||||
_wsystem(L"echo in-jail > chroot-testdir\\jail\\d1\\j.Txt");
|
||||
/* create links to world within jail */
|
||||
_wsystem(L"mklink /D chroot-testdir\\jail\\world-sl ..\\world");
|
||||
_wsystem(L"mklink /J chroot-testdir\\jail\\world-jn chroot-testdir\\world");
|
||||
|
||||
TEST_START("chroot on invalid path");
|
||||
ASSERT_INT_EQ(chroot("blah"), -1);
|
||||
ASSERT_INT_EQ(chroot("\\c:\\blah"), -1);
|
||||
ASSERT_INT_EQ(chroot("/c:/blah"), -1);
|
||||
TEST_DONE();
|
||||
|
||||
TEST_START("access world before chroot");
|
||||
ASSERT_INT_NE(fd = open("chroot-testdir\\jail\\world-jn\\w.Txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_PTR_NE(f = fopen("chroot-testdir\\jail\\world-jn\\w.Txt", "r"), NULL);
|
||||
fclose(f);
|
||||
TEST_DONE();
|
||||
|
||||
TEST_START("real chroot now");
|
||||
getcwd(path, MAX_PATH);
|
||||
getcwd(test_root, MAX_PATH);
|
||||
strcat(path, "\\chroot-testdir\\jail");
|
||||
ASSERT_INT_EQ(chdir(path), 0);
|
||||
ASSERT_INT_EQ(chroot(path), 0);
|
||||
TEST_DONE();
|
||||
|
||||
TEST_START("chdir; getcwd and realpath");
|
||||
ASSERT_PTR_NE(getcwd(path, MAX_PATH), NULL);
|
||||
ASSERT_STRING_EQ(path, "\\");
|
||||
ASSERT_INT_NE(chdir(test_root), 0);
|
||||
ASSERT_INT_EQ(chdir("d1"), 0);
|
||||
ASSERT_PTR_NE(realpath("..", path), NULL);
|
||||
ASSERT_STRING_EQ(path, "/");
|
||||
ASSERT_PTR_NE(getcwd(path, MAX_PATH), NULL);
|
||||
ASSERT_STRING_EQ(path, "\\d1");
|
||||
ASSERT_PTR_NE(realpath(".", path), NULL);
|
||||
ASSERT_STRING_EQ(path, "/d1");
|
||||
ASSERT_PTR_EQ(realpath("..\\..\\", path), NULL);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
TEST_DONE();
|
||||
|
||||
TEST_START("file io within jail");
|
||||
ASSERT_INT_NE(fd = open("\\d1\\j.txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_INT_NE(fd = open("\\d1/j.txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_INT_NE(fd = open("/d1/j.txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_INT_NE(fd = open("/dev/null", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_PTR_NE(f = fopen("\\d1\\j.txt", "r"), NULL);
|
||||
fclose(f);
|
||||
ASSERT_PTR_NE(f = fopen("/dev/null", "w"), NULL);
|
||||
fclose(f);
|
||||
ASSERT_INT_EQ(chdir("/"), 0);
|
||||
ASSERT_INT_NE(fd = open("d1/j.txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_PTR_NE(f = fopen("d1\\j.txt", "r"), NULL);
|
||||
fclose(f);
|
||||
ASSERT_INT_EQ(chdir("\\d1"), 0);
|
||||
ASSERT_INT_NE(fd = open("j.txt", 0), -1);
|
||||
close(fd);
|
||||
ASSERT_PTR_NE(f = fopen("j.txt", "r"), NULL);
|
||||
fclose(f);
|
||||
TEST_DONE();
|
||||
|
||||
TEST_START("access world after chroot");
|
||||
ASSERT_INT_EQ(chdir("/"), 0);
|
||||
ASSERT_INT_EQ(fd = open(test_root, 0), -1);
|
||||
ASSERT_INT_EQ(errno, ENOENT);
|
||||
ASSERT_INT_EQ(fd = open("..\\", 0), -1);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
ASSERT_INT_EQ(fd = open("../", 0), -1);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
ASSERT_INT_EQ(fd = open("../outofjail.txt", O_CREAT), -1);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
/* ensure outofjail.txt is not created by the above call*/
|
||||
path[0] = '\0';
|
||||
strcat(path, test_root);
|
||||
strcat(path, "\\chroot-testdir\\outofjail.txt");
|
||||
ASSERT_INT_EQ(fd = _open(path, 0), -1);
|
||||
ASSERT_INT_EQ(errno, ENOENT);
|
||||
ASSERT_INT_EQ(fd = open("world-jn\\w.Txt", 0), -1);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
ASSERT_PTR_EQ(f = fopen("world-jn\\w.Txt", "r"), NULL);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
ASSERT_INT_EQ(fd = open("world-sl\\w.Txt", 0), -1);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
ASSERT_PTR_EQ(f = fopen("world-sl\\w.Txt", "r"), NULL);
|
||||
ASSERT_INT_EQ(errno, EACCES);
|
||||
TEST_DONE();
|
||||
|
||||
|
||||
//_wsystem(L"RD /S /Q chroot-testdir >NUL 2>&1");
|
||||
}
|
||||
|
||||
void
|
||||
miscellaneous_tests()
|
||||
{
|
||||
@ -199,4 +320,5 @@ miscellaneous_tests()
|
||||
test_pw();
|
||||
test_realpath();
|
||||
test_statvfs();
|
||||
test_chroot();
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ extern void log_init(char *av0, int level, int facility, int on_stderr);
|
||||
void
|
||||
tests()
|
||||
{
|
||||
_set_abort_behavior(0, 1);
|
||||
log_init(NULL, 7, 2, 0);
|
||||
_set_abort_behavior(0, 1);
|
||||
log_init(NULL, 7, 2, 0);
|
||||
signal_tests();
|
||||
socket_tests();
|
||||
file_tests();
|
||||
dir_tests();
|
||||
str_tests();
|
||||
miscellaneous_tests();
|
||||
socket_tests();
|
||||
file_tests();
|
||||
dir_tests();
|
||||
str_tests();
|
||||
miscellaneous_tests();
|
||||
}
|
||||
|
||||
char *
|
||||
|
24
session.c
24
session.c
@ -438,7 +438,7 @@ int register_child(void* child, unsigned long pid);
|
||||
int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
int pipein[2], pipeout[2], pipeerr[2], r;
|
||||
char *exec_command = NULL, *progdir = w32_programdir(), *cmd = NULL, *shell_host = NULL, *command_b64 = NULL;
|
||||
wchar_t *exec_command_w = NULL, *pw_dir_w;
|
||||
wchar_t *exec_command_w = NULL;
|
||||
const char *sftp_exe = "sftp-server.exe", *argp = NULL;
|
||||
size_t command_b64_len = 0;
|
||||
PROCESS_INFORMATION pi;
|
||||
@ -457,9 +457,6 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
if (pipe(pipein) == -1 || pipe(pipeout) == -1 || pipe(pipeerr) == -1)
|
||||
fatal("%s: cannot create pipe: %.100s", __func__, strerror(errno));
|
||||
|
||||
if ((pw_dir_w = utf8_to_utf16(s->pw->pw_dir)) == NULL)
|
||||
fatal("%s: out of memory", __func__);
|
||||
|
||||
set_nonblock(pipein[0]);
|
||||
set_nonblock(pipein[1]);
|
||||
set_nonblock(pipeout[0]);
|
||||
@ -474,6 +471,9 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
/* setup Environment varibles */
|
||||
setup_session_vars(s);
|
||||
|
||||
if (!in_chroot)
|
||||
chdir(s->pw->pw_dir);
|
||||
|
||||
/* prepare exec - path used with CreateProcess() */
|
||||
if (s->is_subsystem || (command && memcmp(command, "scp", 3) == 0)) {
|
||||
/* relative or absolute */
|
||||
@ -564,10 +564,9 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
|
||||
debug("Executing command: %s", exec_command);
|
||||
UTF8_TO_UTF16_FATAL(exec_command_w, exec_command);
|
||||
|
||||
/* in debug mode launch using sshd.exe user context */
|
||||
|
||||
create_process_ret_val = CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE,
|
||||
DETACHED_PROCESS, NULL, pw_dir_w,
|
||||
DETACHED_PROCESS, NULL, NULL,
|
||||
&si, &pi);
|
||||
|
||||
if (!create_process_ret_val)
|
||||
@ -598,8 +597,7 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
||||
else
|
||||
session_set_fds(ssh, s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 1); /* tty interactive session */
|
||||
|
||||
free(pw_dir_w);
|
||||
free(exec_command_w);
|
||||
free(exec_command_w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1536,11 +1534,15 @@ safely_chroot(const char *path, uid_t uid)
|
||||
char component[PATH_MAX];
|
||||
struct stat st;
|
||||
|
||||
#ifdef WINDOWS
|
||||
if (path[1] != ':')
|
||||
#else
|
||||
if (*path != '/')
|
||||
#endif
|
||||
fatal("chroot path does not begin at root");
|
||||
if (strlen(path) >= sizeof(component))
|
||||
fatal("chroot path too long");
|
||||
|
||||
#ifndef WINDOWS
|
||||
/*
|
||||
* Descend the path, checking that each component is a
|
||||
* root-owned directory with strict permissions.
|
||||
@ -1568,7 +1570,7 @@ safely_chroot(const char *path, uid_t uid)
|
||||
cp == NULL ? "" : "component ", component);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
if (chdir(path) == -1)
|
||||
fatal("Unable to chdir to chroot path \"%s\": "
|
||||
"%s", path, strerror(errno));
|
||||
|
Loading…
x
Reference in New Issue
Block a user