From e393499ff89eaa8c4d5dafce9d4e5f3cd5f94eea Mon Sep 17 00:00:00 2001 From: Norbert Federa Date: Tue, 2 Sep 2014 15:42:44 +0200 Subject: [PATCH] rdpdr/drive: fixes for hung peers & info requests drive_file_init: only allow directories and regular files This is fixes issue #2071 Even if the server is only interested in getting a file's or directory's attributes FreeRDP still tries to open the object with read permissions. If the FreeRDP client has no read permissions for this object the call will fail which forces the server to perform some expensive workarounds (e.g. getting to the stat buffers via a directory enumeration request). On Linux we can try to open the file or directory with the O_PATH flag in order to obtain a file descriptor who's only purpose is to perform operations that act purely at the file descriptor level. --- channels/drive/client/drive_file.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index ab3e96837..5f3aa4718 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -49,7 +49,9 @@ #endif #ifdef HAVE_FCNTL_H +#define __USE_GNU /* for O_PATH */ #include +#undef __USE_GNU #endif #ifdef _WIN32 @@ -192,6 +194,11 @@ static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 Creat if (STAT(file->fullpath, &st) == 0) { file->is_dir = (S_ISDIR(st.st_mode) ? TRUE : FALSE); + if (!file->is_dir && !S_ISREG(st.st_mode)) + { + file->err = EPERM; + return TRUE; + } #ifndef WIN32 if (st.st_size > (unsigned long) 0x07FFFFFFF) largeFile = TRUE; @@ -306,6 +313,25 @@ DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id, return NULL; } +#if defined(__linux__) && defined(O_PATH) + if (file->fd < 0 && file->err == EACCES) + { + /** + * We have no access permissions for the file or directory but if the + * peer is only interested in reading the object's attributes we can try + * to obtain a file descriptor who's only purpose is to perform + * operations that act purely at the file descriptor level. + * See open(2) + **/ + { + if ((file->fd = OPEN(file->fullpath, O_PATH)) >= 0) + { + file->err = 0; + } + } + } +#endif + return file; }