mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-22 05:24:43 +02:00
Add driver letter support to sftp-server and let it form external path with / to meet spec
sftp-server now conforms to sftp rfc spec and creates external path with / as the first character so that programs like Winscp will now work. Driver letters are kept below it like /x:/users/user1homedir format; driver letters are now supported. cd /users or cd c:/users or cd D:/users will all work now. Windows security enforces what directory or files one can view/access.
This commit is contained in:
parent
102d1ed6b6
commit
4857c272b9
@ -210,7 +210,7 @@ char *realpathWin32(const char *path, char resolved[PATH_MAX])
|
|||||||
char realpath[PATH_MAX];
|
char realpath[PATH_MAX];
|
||||||
char * pch;
|
char * pch;
|
||||||
|
|
||||||
path_len = strlcpy(realpath, path, sizeof(realpath));
|
path_len = strlcpy(realpath, path+1, sizeof(realpath));
|
||||||
|
|
||||||
char * pchMac;
|
char * pchMac;
|
||||||
pchMac = strstr (realpath, "._");
|
pchMac = strstr (realpath, "._");
|
||||||
@ -247,12 +247,69 @@ char *realpathWin32(const char *path, char resolved[PATH_MAX])
|
|||||||
|
|
||||||
if (realpath[1] == ':' && realpath[2] == 0)
|
if (realpath[1] == ':' && realpath[2] == 0)
|
||||||
{
|
{
|
||||||
realpath[2] = '\\';
|
realpath[2] = '/';
|
||||||
realpath[3] = 0;
|
realpath[3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy (resolved, realpath, sizeof(realpath));
|
resolved[0] = *path; // will be our first slash in /x:/users/test1 format
|
||||||
|
strncpy (resolved+1, realpath, sizeof(realpath));
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *realpathWin32i(const char *path, char resolved[PATH_MAX])
|
||||||
|
{
|
||||||
|
size_t path_len;
|
||||||
|
unsigned int lastSlash;
|
||||||
|
char realpath[PATH_MAX];
|
||||||
|
char * pch;
|
||||||
|
|
||||||
|
if (path[0] != '/') {
|
||||||
|
// absolute form x:/abc/def given, no first slash to take out
|
||||||
|
path_len = strlcpy(realpath, path, sizeof(realpath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
path_len = strlcpy(realpath, path + 1, sizeof(realpath));
|
||||||
|
|
||||||
|
char * pchMac;
|
||||||
|
pchMac = strstr(realpath, "._");
|
||||||
|
if (pchMac != NULL)
|
||||||
|
{
|
||||||
|
pchMac[0] = '\0';
|
||||||
|
pchMac++;
|
||||||
|
pchMac++;
|
||||||
|
strcat(realpath, pchMac);
|
||||||
|
}
|
||||||
|
|
||||||
|
pch = strrchr(realpath, '/');
|
||||||
|
lastSlash = pch - realpath + 1;
|
||||||
|
if (path_len == lastSlash)
|
||||||
|
{
|
||||||
|
realpath[lastSlash - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
pch = strrchr(realpath, '.');
|
||||||
|
if (pch != NULL)
|
||||||
|
{
|
||||||
|
if (realpath[pch - realpath - 1] == '.')
|
||||||
|
{
|
||||||
|
realpath[pch - realpath - 2] = '\0';
|
||||||
|
pch = strrchr(realpath, '/');
|
||||||
|
if (pch != NULL)
|
||||||
|
realpath[pch - realpath] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store terminating slash in 'X:/' on Windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (realpath[1] == ':' && realpath[2] == 0)
|
||||||
|
{
|
||||||
|
realpath[2] = '/';
|
||||||
|
realpath[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(resolved, realpath, sizeof(realpath));
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
#endif /* WIN32_FIXME */
|
#endif /* WIN32_FIXME */
|
||||||
|
120
sftp-server.c
120
sftp-server.c
@ -772,6 +772,15 @@ process_open(u_int32_t id)
|
|||||||
debug3("request %u: open flags %d", id, pflags);
|
debug3("request %u: open flags %d", id, pflags);
|
||||||
flags = flags_from_portable(pflags);
|
flags = flags_from_portable(pflags);
|
||||||
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
|
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(name, resolvedname))
|
||||||
|
{
|
||||||
|
free(name);
|
||||||
|
name = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
logit("open \"%s\" flags %s mode 0%o",
|
logit("open \"%s\" flags %s mode 0%o",
|
||||||
name, string_from_portable(pflags), mode);
|
name, string_from_portable(pflags), mode);
|
||||||
if (readonly &&
|
if (readonly &&
|
||||||
@ -915,10 +924,9 @@ process_do_stat(u_int32_t id, int do_lstat)
|
|||||||
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
|
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
|
|
||||||
if (realpathWin32(name, resolvedname))
|
if (realpathWin32i(name, resolvedname))
|
||||||
{
|
{
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
name = strdup(resolvedname);
|
name = strdup(resolvedname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,10 +1138,19 @@ process_opendir(u_int32_t id)
|
|||||||
|
|
||||||
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
|
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
|
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(path, resolvedname))
|
||||||
|
{
|
||||||
|
free(path);
|
||||||
|
path = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
debug3("request %u: opendir", id);
|
debug3("request %u: opendir", id);
|
||||||
logit("opendir \"%s\"", path);
|
logit("opendir \"%s\"", path);
|
||||||
|
|
||||||
dirp = opendir(path);
|
dirp = opendir(path);
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
status = errno_to_portable(errno);
|
status = errno_to_portable(errno);
|
||||||
@ -1238,6 +1255,17 @@ process_remove(u_int32_t id)
|
|||||||
|
|
||||||
debug3("request %u: remove", id);
|
debug3("request %u: remove", id);
|
||||||
logit("remove name \"%s\"", name);
|
logit("remove name \"%s\"", name);
|
||||||
|
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(name, resolvedname))
|
||||||
|
{
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
name = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
r = unlink(name);
|
r = unlink(name);
|
||||||
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
||||||
send_status(id, status);
|
send_status(id, status);
|
||||||
@ -1261,6 +1289,16 @@ process_mkdir(u_int32_t id)
|
|||||||
a.perm & 07777 : 0777;
|
a.perm & 07777 : 0777;
|
||||||
debug3("request %u: mkdir", id);
|
debug3("request %u: mkdir", id);
|
||||||
logit("mkdir name \"%s\" mode 0%o", name, mode);
|
logit("mkdir name \"%s\" mode 0%o", name, mode);
|
||||||
|
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(name, resolvedname))
|
||||||
|
{
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
name = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
r = mkdir(name, mode);
|
r = mkdir(name, mode);
|
||||||
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
||||||
send_status(id, status);
|
send_status(id, status);
|
||||||
@ -1278,6 +1316,15 @@ process_rmdir(u_int32_t id)
|
|||||||
|
|
||||||
debug3("request %u: rmdir", id);
|
debug3("request %u: rmdir", id);
|
||||||
logit("rmdir name \"%s\"", name);
|
logit("rmdir name \"%s\"", name);
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(name, resolvedname))
|
||||||
|
{
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
name = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
r = rmdir(name);
|
r = rmdir(name);
|
||||||
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
||||||
send_status(id, status);
|
send_status(id, status);
|
||||||
@ -1306,7 +1353,11 @@ process_realpath(u_int32_t id)
|
|||||||
#else
|
#else
|
||||||
if ( (path[0] == '\0') || ( strcmp(path, ".")== 0 ) ) {
|
if ( (path[0] == '\0') || ( strcmp(path, ".")== 0 ) ) {
|
||||||
free(path);
|
free(path);
|
||||||
_getcwd(resolvedname, sizeof(resolvedname));
|
// add an extra / in front of paths to make them sftp spec compliant
|
||||||
|
// c:/users/test1 will become /c:/users/test1
|
||||||
|
resolvedname[0] = '/';
|
||||||
|
|
||||||
|
_getcwd(&resolvedname[1], sizeof(resolvedname));
|
||||||
// convert back slashes to forward slashes to be compatibale with unix naming
|
// convert back slashes to forward slashes to be compatibale with unix naming
|
||||||
char *cptr = resolvedname;
|
char *cptr = resolvedname;
|
||||||
while (*cptr) {
|
while (*cptr) {
|
||||||
@ -1314,8 +1365,36 @@ process_realpath(u_int32_t id)
|
|||||||
*cptr = '/' ;
|
*cptr = '/' ;
|
||||||
cptr++;
|
cptr++;
|
||||||
}
|
}
|
||||||
path = xstrdup(resolvedname);
|
path = strdup(resolvedname);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// see if we were given rooted form /dir or /x:/home/x:/dir
|
||||||
|
if (path[2] != ':') {
|
||||||
|
// absolute form given /dir
|
||||||
|
// no drive letter, so was given in absolute form like cd /debug and we got "/debug" to process
|
||||||
|
// we have to attach current drive letter in front
|
||||||
|
resolvedname[0] = '/';
|
||||||
|
resolvedname[1] = _getdrive() + 'A' - 1; // convert current drive letter to Windows driver Char
|
||||||
|
resolvedname[2] = ':';
|
||||||
|
strcpy(&resolvedname[3], path);
|
||||||
|
free(path);
|
||||||
|
path = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char *pch = strchr(path, ':');
|
||||||
|
if (pch != NULL && (pch = strrchr(pch+1, ':')) ) {
|
||||||
|
if (path[0] == '/') { // it was /x:/home/x:/dir form, use last drive letter part
|
||||||
|
pch--;
|
||||||
|
resolvedname[0] = '/';
|
||||||
|
strcpy(resolvedname+1, pch);
|
||||||
|
free(path);
|
||||||
|
path = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
debug3("request %u: realpath", id);
|
debug3("request %u: realpath", id);
|
||||||
@ -1341,7 +1420,19 @@ process_rename(u_int32_t id)
|
|||||||
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
|
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
|
||||||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
|
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(oldpath, resolvedname))
|
||||||
|
{
|
||||||
|
free(oldpath);
|
||||||
|
oldpath = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
if (realpathWin32i(newpath, resolvedname))
|
||||||
|
{
|
||||||
|
free(newpath);
|
||||||
|
newpath = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
debug3("request %u: rename", id);
|
debug3("request %u: rename", id);
|
||||||
logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
|
logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
|
||||||
@ -1502,6 +1593,19 @@ process_extended_posix_rename(u_int32_t id)
|
|||||||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
|
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
|
|
||||||
|
#ifdef WIN32_FIXME
|
||||||
|
char resolvedname[MAXPATHLEN];
|
||||||
|
if (realpathWin32i(oldpath, resolvedname))
|
||||||
|
{
|
||||||
|
free(oldpath);
|
||||||
|
oldpath = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
if (realpathWin32i(newpath, resolvedname))
|
||||||
|
{
|
||||||
|
free(newpath);
|
||||||
|
newpath = strdup(resolvedname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
debug3("request %u: posix-rename", id);
|
debug3("request %u: posix-rename", id);
|
||||||
logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
|
logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
|
||||||
@ -1707,6 +1811,8 @@ if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
|
|||||||
#ifndef WIN32_FIXME
|
#ifndef WIN32_FIXME
|
||||||
r = link(oldpath, newpath);
|
r = link(oldpath, newpath);
|
||||||
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
||||||
|
#else
|
||||||
|
status = SSH2_FX_OP_UNSUPPORTED;
|
||||||
#endif
|
#endif
|
||||||
send_status(id, status);
|
send_status(id, status);
|
||||||
free(oldpath);
|
free(oldpath);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user