Skip to content

Commit 8c92d7b

Browse files
committed
fix sftp-server to be able to show directories that are linked to other point
"Application Data" is one such directory in a user;'s home directory. We get inside path of to find where a directory is linked to and read that to get contents.
1 parent 46327a9 commit 8c92d7b

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

sftp-common.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,160 @@ strmode(mode_t mode, char *p)
403403
*p++ = ' '; /* will be a '+' if ACL's implemented */
404404
*p = '\0';
405405
}
406+
407+
#include <winioctl.h>
408+
// Maximum reparse buffer info size. The max user defined reparse
409+
// data is 16KB, plus there's a header.
410+
//
411+
#define MAX_REPARSE_SIZE 17000
412+
413+
#define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO
414+
#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) // winnt ntifs
415+
#define IO_REPARSE_TAG_HSM (0xC0000004L) // winnt ntifs
416+
#define IO_REPARSE_TAG_SIS (0x80000007L) // winnt ntifs
417+
418+
419+
//
420+
// Undocumented FSCTL_SET_REPARSE_POINT structure definition
421+
//
422+
#define REPARSE_MOUNTPOINT_HEADER_SIZE 8
423+
typedef struct {
424+
DWORD ReparseTag;
425+
DWORD ReparseDataLength;
426+
WORD Reserved;
427+
WORD ReparseTargetLength;
428+
WORD ReparseTargetMaximumLength;
429+
WORD Reserved1;
430+
WCHAR ReparseTarget[1];
431+
} REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER;
432+
433+
434+
typedef struct _REPARSE_DATA_BUFFER {
435+
ULONG ReparseTag;
436+
USHORT ReparseDataLength;
437+
USHORT Reserved;
438+
union {
439+
struct {
440+
USHORT SubstituteNameOffset;
441+
USHORT SubstituteNameLength;
442+
USHORT PrintNameOffset;
443+
USHORT PrintNameLength;
444+
WCHAR PathBuffer[1];
445+
} SymbolicLinkReparseBuffer;
446+
struct {
447+
USHORT SubstituteNameOffset;
448+
USHORT SubstituteNameLength;
449+
USHORT PrintNameOffset;
450+
USHORT PrintNameLength;
451+
WCHAR PathBuffer[1];
452+
} MountPointReparseBuffer;
453+
struct {
454+
UCHAR DataBuffer[1];
455+
} GenericReparseBuffer;
456+
};
457+
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
458+
459+
BOOL ResolveLink(char * tLink, char *ret, DWORD * plen, DWORD Flags)
460+
{
461+
HANDLE fileHandle;
462+
BYTE reparseBuffer[MAX_REPARSE_SIZE];
463+
PBYTE reparseData;
464+
PREPARSE_GUID_DATA_BUFFER reparseInfo = (PREPARSE_GUID_DATA_BUFFER)reparseBuffer;
465+
PREPARSE_DATA_BUFFER msReparseInfo = (PREPARSE_DATA_BUFFER)reparseBuffer;
466+
DWORD returnedLength;
467+
468+
if (Flags & FILE_ATTRIBUTE_DIRECTORY)
469+
{
470+
fileHandle = CreateFile(tLink, 0,
471+
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
472+
OPEN_EXISTING,
473+
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
474+
475+
}
476+
else {
477+
478+
//
479+
// Open the file
480+
//
481+
fileHandle = CreateFile(tLink, 0,
482+
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
483+
OPEN_EXISTING,
484+
FILE_FLAG_OPEN_REPARSE_POINT, 0);
485+
}
486+
if (fileHandle == INVALID_HANDLE_VALUE)
487+
{
488+
sprintf_s(ret, *plen, "%s", tLink);
489+
return TRUE;
490+
}
491+
492+
if (GetFileAttributes(tLink) & FILE_ATTRIBUTE_REPARSE_POINT) {
493+
494+
if (DeviceIoControl(fileHandle, FSCTL_GET_REPARSE_POINT,
495+
NULL, 0, reparseInfo, sizeof(reparseBuffer),
496+
&returnedLength, NULL)) {
497+
498+
if (IsReparseTagMicrosoft(reparseInfo->ReparseTag)) {
499+
500+
switch (reparseInfo->ReparseTag) {
501+
case 0x80000000 | IO_REPARSE_TAG_SYMBOLIC_LINK:
502+
case IO_REPARSE_TAG_MOUNT_POINT:
503+
if (*plen >= msReparseInfo->MountPointReparseBuffer.SubstituteNameLength)
504+
{
505+
reparseData = (PBYTE)&msReparseInfo->SymbolicLinkReparseBuffer.PathBuffer;
506+
WCHAR temp[1024];
507+
wcsncpy_s(temp, 1024,
508+
(PWCHAR)(reparseData + msReparseInfo->MountPointReparseBuffer.SubstituteNameOffset),
509+
(size_t)msReparseInfo->MountPointReparseBuffer.SubstituteNameLength);
510+
temp[msReparseInfo->MountPointReparseBuffer.SubstituteNameLength] = 0;
511+
sprintf_s(ret, *plen, "%S", &temp[4]);
512+
}
513+
else
514+
{
515+
sprintf_s(ret, *plen, "%s", tLink);
516+
return FALSE;
517+
}
518+
519+
break;
520+
default:
521+
break;
522+
}
523+
}
524+
}
525+
}
526+
else {
527+
sprintf_s(ret, *plen, "%s", tLink);
528+
}
529+
530+
CloseHandle(fileHandle);
531+
return TRUE;
532+
}
533+
534+
char * get_inside_path(char * opath, BOOL bResolve, BOOL bMustExist)
535+
{
536+
BOOL ResolveLink(char * tLink, char *ret, DWORD * plen, DWORD Flags);
537+
538+
char * ipath;
539+
char * temp_name;
540+
char temp[1024];
541+
DWORD templen = sizeof(temp);
542+
WIN32_FILE_ATTRIBUTE_DATA FileInfo;
543+
544+
545+
if (!GetFileAttributesEx(opath, GetFileExInfoStandard, &FileInfo) && bMustExist)
546+
{
547+
return NULL;
548+
}
549+
550+
if (bResolve)
551+
{
552+
ResolveLink(opath, temp, &templen, FileInfo.dwFileAttributes);
553+
ipath = xstrdup(temp);
554+
}
555+
else
556+
{
557+
ipath = xstrdup(opath);
558+
}
559+
560+
return ipath;
561+
}
406562
#endif

sftp-server.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797

9898
#define stat(PATH, BUF) _stat(PATH, BUF)
9999

100+
char * get_inside_path(char *, BOOL, BOOL);
101+
100102
/*
101103
* Function to cut last slash (windows
102104
* stat requires paths
@@ -1141,17 +1143,24 @@ process_opendir(u_int32_t id)
11411143

11421144
#ifdef WIN32_FIXME
11431145
char resolvedname[MAXPATHLEN];
1146+
char * ipath;
11441147
if (realpathWin32i(path, resolvedname))
11451148
{
11461149
free(path);
11471150
path = strdup(resolvedname);
11481151
}
1152+
ipath = get_inside_path(path, TRUE, TRUE);
11491153
#endif
11501154

11511155
debug3("request %u: opendir", id);
11521156
logit("opendir \"%s\"", path);
11531157

1158+
#ifdef WIN32_FIXME
1159+
dirp = opendir(ipath);
1160+
free(ipath);
1161+
#else
11541162
dirp = opendir(path);
1163+
#endif
11551164
if (dirp == NULL) {
11561165
status = errno_to_portable(errno);
11571166
} else {

0 commit comments

Comments
 (0)