From 74fcdaec2071bb23c090bc13b9cfd0c4765ed3bd Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Tue, 2 Jul 2002 01:36:15 +0000 Subject: [PATCH] * autoload.cc (GetSecurityInfo): Define new autoload function. (RegQueryInfoKeyA): Ditto. * fhandler.h (fhandler_virtual::fill_filebuf): Change return type to bool. (fhandler_proc::fill_filebuf): Ditto. (fhandler_registry::fill_filebuf): Ditto. (fhandler_process::fill_filebuf): Ditto. (fhandler_registry::value_name): Add new member. (fhandler_registry::close): Add new method. (fhandler_process::p): Remove member. * fhandler_proc.cc (fhandler_proc::open): Add set_nohandle after calling superclass method. Check return value of fill_filebuf. (fhandler_proc::fill_filebuf): Change return type to bool. Add return statement. * fhandler_process.cc (fhandler_process::open): Add set_nohandle after calling superclass method. Remove references to p. Check return value of fill_filebuf. (fhandler_process::fill_filebuf): Change return type to bool. Don't use dereference operator on p. Add return statement. (fhandler_process::format_process_stat): Fix typo. * fhandler_registry.cc: Add static open_key declaration. (fhandler_registry::exists): Assume path is already normalised. Try opening the path as a key in its own right first, before reverting to enumerating subkeys and values of the parent key. (fhandler_registry::fstat): Add additional code to return more relevant information about the registry key/value. (fhandler_registry::readdir): Explicitly set desired access when opening registry key. Remove output of buf from debug_printf format string. (fhandler_registry::open): Use set_io_handle to store registry key handle. Set value_name member. Move code to read a value from the registry to fill_filebuf. Add call to fill_filebuf. (fhandler_registry::close): New method. (fhandler_registry::fill_filebuf): Change return type to bool. Add code to read a value from registry. (fhandler_registry::open_key): Make function static. Use KEY_READ as desired access unless this is the last path component. Check the return value of RegOpenKeyEx for an error instead of hKey. * fhandler_virtual.cc (fhandler_virtual::lseek): Check the return value of fill_filebuf. (fhandler_virtual::open): Remove call to set_nohandle. (fhandler_virtual::fill_filebuf): Change return type to bool. Add return statement. * security.cc (get_nt_object_attribute): New function. (get_object_attribute): New function. * security.h (get_object_attribute): New function declaration. --- winsup/cygwin/ChangeLog | 51 ++++- winsup/cygwin/autoload.cc | 2 + winsup/cygwin/fhandler.h | 13 +- winsup/cygwin/fhandler_proc.cc | 11 +- winsup/cygwin/fhandler_process.cc | 91 ++++----- winsup/cygwin/fhandler_registry.cc | 313 ++++++++++++++++++++--------- winsup/cygwin/fhandler_virtual.cc | 8 +- winsup/cygwin/security.cc | 169 ++++++++++++++++ winsup/cygwin/security.h | 3 + 9 files changed, 508 insertions(+), 153 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6e8d3933f..093e93e31 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,4 +1,53 @@ -2002-07-01 Pierre Humblet +2002-07-02 Christopher January + + * autoload.cc (GetSecurityInfo): Define new autoload function. + (RegQueryInfoKeyA): Ditto. + * fhandler.h (fhandler_virtual::fill_filebuf): Change return type to + bool. + (fhandler_proc::fill_filebuf): Ditto. + (fhandler_registry::fill_filebuf): Ditto. + (fhandler_process::fill_filebuf): Ditto. + (fhandler_registry::value_name): Add new member. + (fhandler_registry::close): Add new method. + (fhandler_process::p): Remove member. + * fhandler_proc.cc (fhandler_proc::open): Add set_nohandle after + calling superclass method. Check return value of fill_filebuf. + (fhandler_proc::fill_filebuf): Change return type to bool. Add return + statement. + * fhandler_process.cc (fhandler_process::open): Add set_nohandle after + calling superclass method. Remove references to p. Check return value + of fill_filebuf. + (fhandler_process::fill_filebuf): Change return type to bool. Don't + use dereference operator on p. Add return statement. + (fhandler_process::format_process_stat): Fix typo. + * fhandler_registry.cc: Add static open_key declaration. + (fhandler_registry::exists): Assume path is already normalised. Try + opening the path as a key in its own right first, before reverting to + enumerating subkeys and values of the parent key. + (fhandler_registry::fstat): Add additional code to return more relevant + information about the registry key/value. + (fhandler_registry::readdir): Explicitly set desired access when + opening registry key. Remove output of buf from debug_printf format + string. + (fhandler_registry::open): Use set_io_handle to store registry key + handle. Set value_name member. Move code to read a value from the + registry to fill_filebuf. Add call to fill_filebuf. + (fhandler_registry::close): New method. + (fhandler_registry::fill_filebuf): Change return type to bool. Add + code to read a value from registry. + (fhandler_registry::open_key): Make function static. Use KEY_READ as + desired access unless this is the last path component. Check the + return value of RegOpenKeyEx for an error instead of hKey. + * fhandler_virtual.cc (fhandler_virtual::lseek): Check the return value + of fill_filebuf. + (fhandler_virtual::open): Remove call to set_nohandle. + (fhandler_virtual::fill_filebuf): Change return type to bool. Add + return statement. + * security.cc (get_nt_object_attribute): New function. + (get_object_attribute): New function. + * security.h (get_object_attribute): New function declaration. + +2002-07-01 Pierre Humblet * syscalls.c (seteuid32): Do not return an error when the token cannot be created only because of a problem with the gid. diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index d37b19975..5c14ff115 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -326,6 +326,7 @@ LoadDLLfunc (GetLengthSid, 4, advapi32) LoadDLLfunc (GetSecurityDescriptorDacl, 16, advapi32) LoadDLLfunc (GetSecurityDescriptorGroup, 12, advapi32) LoadDLLfunc (GetSecurityDescriptorOwner, 12, advapi32) +LoadDLLfunc (GetSecurityInfo, 32, advapi32) LoadDLLfunc (GetSidIdentifierAuthority, 4, advapi32) LoadDLLfunc (GetSidSubAuthority, 8, advapi32) LoadDLLfunc (GetSidSubAuthorityCount, 4, advapi32) @@ -358,6 +359,7 @@ LoadDLLfunc (RegLoadKeyA, 12, advapi32) LoadDLLfunc (RegEnumKeyExA, 32, advapi32) LoadDLLfunc (RegEnumValueA, 32, advapi32) LoadDLLfunc (RegOpenKeyExA, 20, advapi32) +LoadDLLfunc (RegQueryInfoKeyA, 48, advapi32) LoadDLLfunc (RegQueryValueExA, 24, advapi32) LoadDLLfunc (RegSetValueExA, 24, advapi32) LoadDLLfunc (RegisterEventSourceA, 8, advapi32) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index ebb07a8df..5727d24ab 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1090,7 +1090,7 @@ class fhandler_virtual : public fhandler_base int open (path_conv *, int flags, mode_t mode = 0); int close (void); int __stdcall fstat (struct stat *buf, path_conv *pc) __attribute__ ((regparm (3))); - virtual void fill_filebuf (); + virtual bool fill_filebuf (); }; class fhandler_proc: public fhandler_virtual @@ -1104,11 +1104,13 @@ class fhandler_proc: public fhandler_virtual int open (path_conv *real_path, int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3))); - void fill_filebuf (); + bool fill_filebuf (); }; class fhandler_registry: public fhandler_proc { + private: + char *value_name; public: fhandler_registry (); int exists(); @@ -1120,22 +1122,21 @@ class fhandler_registry: public fhandler_proc int open (path_conv *real_path, int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3))); - HKEY open_key(const char *name, REGSAM access = KEY_READ, bool isValue = false); - void fill_filebuf (); + bool fill_filebuf (); + int close (void); }; class pinfo; class fhandler_process: public fhandler_proc { pid_t pid; - pinfo *p; public: fhandler_process (); int exists(); struct dirent *readdir (DIR *); int open (path_conv *real_path, int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3))); - void fill_filebuf (); + bool fill_filebuf (); }; typedef union diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index fc753312e..97b8a1751 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -216,6 +216,8 @@ fhandler_proc::open (path_conv *pc, int flags, mode_t mode) if (!res) goto out; + set_nohandle (true); + const char *path; path = get_name () + proc_len; @@ -291,7 +293,11 @@ fhandler_proc::open (path_conv *pc, int flags, mode_t mode) } fileid = proc_file_no; - fill_filebuf (); + if (!fill_filebuf ()) + { + res = 0; + goto out; + } if (flags & O_APPEND) position = filesize; @@ -307,7 +313,7 @@ out: return res; } -void +bool fhandler_proc::fill_filebuf () { switch (fileid) @@ -361,6 +367,7 @@ fhandler_proc::fill_filebuf () break; } } + return true; } static diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 2c5eae720..dc885820a 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -41,7 +41,8 @@ static const int PROCESS_CTTY = 11; static const int PROCESS_STAT = 12; static const int PROCESS_STATM = 13; -static const char *process_listing[] = { +static const char * const process_listing[] = +{ ".", "..", "ppid", @@ -59,14 +60,17 @@ static const char *process_listing[] = { NULL }; -static const int PROCESS_LINK_COUNT = (sizeof(process_listing) / sizeof(const char *)) - 1; +static const int PROCESS_LINK_COUNT = + (sizeof(process_listing) / sizeof(const char *)) - 1; static off_t format_process_stat (_pinfo *p, char *destbuf, size_t maxsize); static off_t format_process_status (_pinfo *p, char *destbuf, size_t maxsize); static off_t format_process_statm (_pinfo *p, char *destbuf, size_t maxsize); static int get_process_state (DWORD dwProcessId); -static bool get_mem_values(DWORD dwProcessId, unsigned long *vmsize, unsigned long *vmrss, unsigned long *vmtext, - unsigned long *vmdata, unsigned long *vmlib, unsigned long *vmshare); +static bool get_mem_values(DWORD dwProcessId, unsigned long *vmsize, + unsigned long *vmrss, unsigned long *vmtext, + unsigned long *vmdata, unsigned long *vmlib, + unsigned long *vmshare); /* Returns 0 if path doesn't exist, >0 if path is a directory, * <0 if path is a file. @@ -159,6 +163,8 @@ fhandler_process::open (path_conv *pc, int flags, mode_t mode) if (!res) goto out; + set_nohandle (true); + const char *path; path = get_name () + proc_len + 1; pid = atoi (path); @@ -215,25 +221,17 @@ fhandler_process::open (path_conv *pc, int flags, mode_t mode) goto out; } - { - pinfo p (pid); - if (!p) - { - set_errno (ENOENT); - res = 0; - goto out; - } - fileid = process_file_no; - this->p = &p; - fill_filebuf (); + if (!fill_filebuf ()) + { + res = 0; + goto out; + } if (flags & O_APPEND) position = filesize; else position = 0; - this->p = NULL; - } success: res = 1; @@ -244,20 +242,17 @@ out: return res; } -void +bool fhandler_process::fill_filebuf () { - pinfo pmaybe; + pinfo p (pid); if (!p) { - pmaybe.init (pid); - p = &pmaybe; + set_errno (ENOENT); + return false; } - if (!p) - return; - switch (fileid) { case PROCESS_UID: @@ -268,27 +263,27 @@ fhandler_process::fill_filebuf () case PROCESS_PPID: { if (!filebuf) - filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40); + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40); int num; switch (fileid) { case PROCESS_PPID: - num = (*p)->ppid; + num = p->ppid; break; case PROCESS_UID: - num = (*p)->uid; + num = p->uid; break; case PROCESS_PGID: - num = (*p)->pgid; + num = p->pgid; break; case PROCESS_SID: - num = (*p)->sid; + num = p->sid; break; case PROCESS_GID: - num = (*p)->gid; + num = p->gid; break; case PROCESS_CTTY: - num = (*p)->ctty; + num = p->ctty; break; default: // what's this here for? num = 0; @@ -301,12 +296,12 @@ fhandler_process::fill_filebuf () case PROCESS_EXENAME: { if (!filebuf) - filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = MAX_PATH); - if ((*p)->process_state & (PID_ZOMBIE | PID_EXITED)) + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = MAX_PATH); + if (p->process_state & (PID_ZOMBIE | PID_EXITED)) strcpy (filebuf, ""); else { - mount_table->conv_to_posix_path ((*p)->progname, filebuf, 1); + mount_table->conv_to_posix_path (p->progname, filebuf, 1); int len = strlen (filebuf); if (len > 4) { @@ -321,17 +316,17 @@ fhandler_process::fill_filebuf () case PROCESS_WINPID: { if (!filebuf) - filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40); - __small_sprintf (filebuf, "%d\n", (*p)->dwProcessId); + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40); + __small_sprintf (filebuf, "%d\n", p->dwProcessId); filesize = strlen (filebuf); break; } case PROCESS_WINEXENAME: { - int len = strlen ((*p)->progname); + int len = strlen (p->progname); if (!filebuf) - filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = (len + 2)); - strcpy (filebuf, (*p)->progname); + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = (len + 2)); + strcpy (filebuf, p->progname); filebuf[len] = '\n'; filesize = len + 1; break; @@ -340,27 +335,26 @@ fhandler_process::fill_filebuf () { if (!filebuf) filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048); - filesize = format_process_status ((*p), filebuf, bufalloc); + filesize = format_process_status (*p, filebuf, bufalloc); break; } case PROCESS_STAT: { if (!filebuf) filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048); - filesize = format_process_stat ((*p), filebuf, bufalloc); + filesize = format_process_stat (*p, filebuf, bufalloc); break; } case PROCESS_STATM: { if (!filebuf) filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048); - filesize = format_process_statm ((*p), filebuf, bufalloc); + filesize = format_process_statm (*p, filebuf, bufalloc); break; } } - if (p == &pmaybe) - p = NULL; + return true; } static @@ -375,7 +369,7 @@ format_process_stat (_pinfo *p, char *destbuf, size_t maxsize) vmsize = 0UL, vmrss = 0UL, vmmaxrss = 0UL; int priority = 0; if (p->process_state & (PID_ZOMBIE | PID_EXITED)) - strcpy (cmd, ""); else { strcpy(cmd, p->progname); @@ -598,11 +592,12 @@ static off_t format_process_statm (_pinfo *p, char *destbuf, size_t maxsize) { - unsigned long vmsize = 0UL, vmrss = 0UL, vmtext = 0UL, vmdata = 0UL, vmlib = 0UL, - vmshare = 0UL; + unsigned long vmsize = 0UL, vmrss = 0UL, vmtext = 0UL, vmdata = 0UL, + vmlib = 0UL, vmshare = 0UL; if (wincap.is_winnt ()) { - if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata, &vmlib, &vmshare)) + if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata, + &vmlib, &vmshare)) return 0; } return __small_sprintf (destbuf, "%ld %ld %ld %ld %ld %ld %ld", diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index f8808dfe4..45b8a858b 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -33,7 +33,7 @@ static const int registry_len = sizeof ("registry") - 1; * make up the value index if we are enuerating values. */ static const __off32_t REG_ENUM_VALUES_MASK = 0x8000000; -static const __off32_t REG_POSITION_MASK = 0xffff; +static const __off32_t REG_POSITION_MASK = 0xffff; /* List of root keys in /proc/registry. * Possibly we should filter out those not relevant to the flavour of Windows @@ -49,7 +49,7 @@ static const char *registry_listing[] = "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_DYN_DATA", // 95/98/Me - "HKEY_PERFOMANCE_DATA", // NT/2000/XP + "HKEY_PERFOMANCE_DATA", // NT/2000/XP NULL }; @@ -66,7 +66,7 @@ static const HKEY registry_keys[] = HKEY_PERFORMANCE_DATA }; -static const int ROOT_KEY_COUNT = sizeof(registry_keys) / sizeof(HKEY); +static const int ROOT_KEY_COUNT = sizeof (registry_keys) / sizeof (HKEY); /* These get added to each subdirectory in /proc/registry. * If we wanted to implement writing, we could maybe add a '.writable' entry or @@ -79,11 +79,14 @@ static const char *special_dot_files[] = NULL }; -static const int SPECIAL_DOT_FILE_COUNT = (sizeof(special_dot_files) / sizeof(const char *)) - 1; +static const int SPECIAL_DOT_FILE_COUNT = + (sizeof (special_dot_files) / sizeof (const char *)) - 1; /* Name given to default values */ static const char *DEFAULT_VALUE_NAME = "@"; +static HKEY open_key (const char *name, REGSAM access, bool isValue); + /* Returns 0 if path doesn't exist, >0 if path is a directory, * <0 if path is a file. * @@ -103,10 +106,7 @@ fhandler_registry::exists () const char *path = get_name (); debug_printf ("exists (%s)", path); - path += proc_len + 1 + registry_len; - - while (SLASH_P (*path)) - path++; + path += proc_len + registry_len + 2; if (*path == 0) { file_type = 2; @@ -132,44 +132,52 @@ fhandler_registry::exists () goto out; } - hKey = open_key (path, KEY_READ, true); - if (hKey == (HKEY) INVALID_HANDLE_VALUE) - return 0; + hKey = open_key (path, KEY_READ, false); + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + file_type = 1; + else + { + hKey = open_key (path, KEY_READ, true); + if (hKey == (HKEY) INVALID_HANDLE_VALUE) + return 0; - while (ERROR_SUCCESS == - (error = RegEnumKeyEx (hKey, index++, buf, &buf_size, NULL, NULL, - NULL, NULL)) || (error == ERROR_MORE_DATA)) - { - if (pathmatch (buf, file)) + while (ERROR_SUCCESS == + (error = RegEnumKeyEx (hKey, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) + || (error == ERROR_MORE_DATA)) { - file_type = 1; + if (pathmatch (buf, file)) + { + file_type = 1; + goto out; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); goto out; } + index = 0; buf_size = MAX_PATH; - } - if (error != ERROR_NO_MORE_ITEMS) - { - seterrno_from_win_error (__FILE__, __LINE__, error); - goto out; - } - index = 0; - buf_size = MAX_PATH; - while (ERROR_SUCCESS == - (error = RegEnumValue (hKey, index++, buf, &buf_size, NULL, NULL, - NULL, NULL)) || (error == ERROR_MORE_DATA)) - { - if (pathmatch (buf, file) || (buf[0] == '\0' && - pathmatch (file, DEFAULT_VALUE_NAME))) + while (ERROR_SUCCESS == + (error = RegEnumValue (hKey, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) + || (error == ERROR_MORE_DATA)) { - file_type = -1; + if (pathmatch (buf, file) || (buf[0] == '\0' && + pathmatch (file, DEFAULT_VALUE_NAME))) + { + file_type = -1; + goto out; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); goto out; } - buf_size = MAX_PATH; - } - if (error != ERROR_NO_MORE_ITEMS) - { - seterrno_from_win_error (__FILE__, __LINE__, error); - goto out; } out: if (hKey != (HKEY) INVALID_HANDLE_VALUE) @@ -178,12 +186,12 @@ out: } fhandler_registry::fhandler_registry (): - fhandler_proc (FH_REGISTRY) +fhandler_proc (FH_REGISTRY) { } int -fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc) +fhandler_registry::fstat (struct __stat64 *buf, path_conv * pc) { this->fhandler_base::fstat (buf, pc); buf->st_mode &= ~_IFMT & NO_W; @@ -206,6 +214,61 @@ fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc) buf->st_mode &= NO_X; break; } + if (file_type != 0 && file_type != 2) + { + HKEY hKey; + const char *path = get_name () + proc_len + registry_len + 2; + hKey = + open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, + (file_type < 0) ? true : false); + + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + { + FILETIME ftLastWriteTime; + DWORD subkey_count; + if (ERROR_SUCCESS == + RegQueryInfoKey (hKey, NULL, NULL, NULL, &subkey_count, NULL, + NULL, NULL, NULL, NULL, NULL, + &ftLastWriteTime)) + { + to_timestruc_t (&ftLastWriteTime, &buf->st_mtim); + buf->st_ctim = buf->st_mtim; + time_as_timestruc_t (&buf->st_atim); + if (file_type > 0) + buf->st_nlink = subkey_count; + else + { + int pathlen = strlen (path); + const char *value_name = path + pathlen - 1; + if (SLASH_P (*value_name) && pathlen > 1) + value_name--; + while (!SLASH_P (*value_name)) + value_name--; + value_name++; + DWORD dwSize; + if (ERROR_SUCCESS == + RegQueryValueEx (hKey, value_name, NULL, NULL, NULL, + &dwSize)) + buf->st_size = dwSize; + } + __uid32_t uid; + __gid32_t gid; + if (get_object_attribute + ((HANDLE) hKey, SE_REGISTRY_KEY, &buf->st_mode, &uid, + &gid) == 0) + { + buf->st_uid = uid; + buf->st_gid = gid; + buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + if (file_type > 0) + buf->st_mode |= S_IFDIR; + else + buf->st_mode &= NO_X; + } + } + RegCloseKey (hKey); + } + } return 0; } @@ -230,14 +293,15 @@ fhandler_registry::readdir (DIR * dir) if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { - handle = open_key (path + 1); - dir->__d_u.__d_data.__handle = handle;; + handle = open_key (path + 1, KEY_READ, false); + dir->__d_u.__d_data.__handle = handle; } if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) goto out; if (dir->__d_position < SPECIAL_DOT_FILE_COUNT) { - strcpy (dir->__d_dirent->d_name, special_dot_files[dir->__d_position++]); + strcpy (dir->__d_dirent->d_name, + special_dot_files[dir->__d_position++]); res = dir->__d_dirent; goto out; } @@ -252,7 +316,8 @@ retry: else error = RegEnumKeyEx ((HKEY) dir->__d_u.__d_data.__handle, dir->__d_position - - SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL, NULL); + SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL, + NULL); if (error == ERROR_NO_MORE_ITEMS && (dir->__d_position & REG_ENUM_VALUES_MASK) == 0) { @@ -280,7 +345,7 @@ retry: dir->__d_position += 0x10000; res = dir->__d_dirent; out: - syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, buf); + syscall_printf ("%p = readdir (%p)", &dir->__d_dirent, dir); return res; } @@ -329,13 +394,11 @@ fhandler_registry::closedir (DIR * dir) } int -fhandler_registry::open (path_conv *pc, int flags, mode_t mode) +fhandler_registry::open (path_conv * pc, int flags, mode_t mode) { - DWORD type, size; - LONG error; - HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; int pathlen; const char *file; + HKEY handle; int res = fhandler_virtual::open (pc, flags, mode); if (!res) @@ -418,33 +481,88 @@ fhandler_registry::open (path_conv *pc, int flags, mode_t mode) goto out; } - hKey = open_key (path, KEY_READ, true); - if (hKey == (HKEY) INVALID_HANDLE_VALUE) + handle = open_key (path, KEY_READ, true); + if (handle == (HKEY) INVALID_HANDLE_VALUE) { res = 0; goto out; } - if (pathmatch (file, DEFAULT_VALUE_NAME)) - file = ""; - if (hKey != HKEY_PERFORMANCE_DATA) + set_io_handle (handle); + + if (pathmatch (file, DEFAULT_VALUE_NAME)) + value_name = cstrdup (""); + else + value_name = cstrdup (file); + + if (!fill_filebuf ()) { - error = RegQueryValueEx (hKey, file, NULL, &type, NULL, &size); + RegCloseKey (handle); + res = 0; + goto out; + } + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_flags ((flags & ~O_TEXT) | O_BINARY); + set_open_status (); +out: + syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode); + return res; +} + +int +fhandler_registry::close () +{ + int res = fhandler_virtual::close (); + if (res != 0) + return res; + HKEY handle = (HKEY) get_handle (); + if (handle != (HKEY) INVALID_HANDLE_VALUE) + { + if (RegCloseKey (handle) != ERROR_SUCCESS) + { + __seterrno (); + res = -1; + } + } + if (value_name) + cfree (value_name); + return 0; +} + +bool +fhandler_registry::fill_filebuf () +{ + DWORD type, size; + LONG error; + HKEY handle = (HKEY) get_handle (); + if (handle != HKEY_PERFORMANCE_DATA) + { + error = RegQueryValueEx (handle, value_name, NULL, &type, NULL, &size); if (error != ERROR_SUCCESS) { - seterrno_from_win_error (__FILE__, __LINE__, error); - res = -1; - goto out; + if (error != ERROR_FILE_NOT_FOUND) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return false; + } + goto value_not_found; } bufalloc = size; filebuf = (char *) cmalloc (HEAP_BUF, bufalloc); error = - RegQueryValueEx (hKey, file, NULL, NULL, (BYTE *) filebuf, &size); + RegQueryValueEx (handle, value_name, NULL, NULL, (BYTE *) filebuf, + &size); if (error != ERROR_SUCCESS) { seterrno_from_win_error (__FILE__, __LINE__, error); - res = 0; - goto out; + return true; } filesize = size; } @@ -460,43 +578,49 @@ fhandler_registry::open (path_conv *pc, int flags, mode_t mode) filebuf = (char *) cmalloc (HEAP_BUF, bufalloc); } error = - RegQueryValueEx (hKey, file, NULL, &type, (BYTE *) filebuf, - &size); - if (error != ERROR_SUCCESS && res != ERROR_MORE_DATA) + RegQueryValueEx (handle, value_name, NULL, &type, + (BYTE *) filebuf, &size); + if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA) { - seterrno_from_win_error (__FILE__, __LINE__, error); - res = 0; - goto out; + if (error != ERROR_FILE_NOT_FOUND) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return true; + } + goto value_not_found; } } while (error == ERROR_MORE_DATA); filesize = size; } - - if (flags & O_APPEND) - position = filesize; - else - position = 0; - -success: - res = 1; - set_flags ((flags & ~O_TEXT) | O_BINARY); - set_open_status (); -out: - if (hKey != (HKEY) INVALID_HANDLE_VALUE) - RegCloseKey (hKey); - syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode); - return res; -} - -void -fhandler_registry::fill_filebuf () -{ + return true; +value_not_found: + DWORD buf_size = MAX_PATH; + char buf[buf_size]; + int index = 0; + while (ERROR_SUCCESS == + (error = RegEnumKeyEx (handle, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) || (error == ERROR_MORE_DATA)) + { + if (pathmatch (buf, value_name)) + { + set_errno (EISDIR); + return false; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return false; + } + set_errno (ENOENT); + return false; } /* Auxillary member function to open registry keys. */ -HKEY -fhandler_registry::open_key (const char *name, REGSAM access, bool isValue) +static HKEY +open_key (const char *name, REGSAM access, bool isValue) { HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; HKEY hParentKey = (HKEY) INVALID_HANDLE_VALUE; @@ -517,10 +641,15 @@ fhandler_registry::open_key (const char *name, REGSAM access, bool isValue) if (hParentKey != (HKEY) INVALID_HANDLE_VALUE) { - hKey = (HKEY) INVALID_HANDLE_VALUE; - LONG error = RegOpenKeyEx (hParentKey, component, 0, access, &hKey); - if (hKey == (HKEY) INVALID_HANDLE_VALUE) + REGSAM effective_access = KEY_READ; + if ((strchr (name, '/') == NULL && isValue == true) || *name == 0) + effective_access = access; + LONG + error = + RegOpenKeyEx (hParentKey, component, 0, effective_access, &hKey); + if (error != ERROR_SUCCESS) { + hKey = (HKEY) INVALID_HANDLE_VALUE; seterrno_from_win_error (__FILE__, __LINE__, error); return hKey; } diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index fb1ed7d39..7f1f02f12 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -115,7 +115,8 @@ fhandler_virtual::lseek (__off64_t offset, int whence) * On Linux, when you lseek within a /proc file, * the contents of the file are updated. */ - fill_filebuf (); + if (!fill_filebuf ()) + return (__off64_t) -1; switch (whence) { case SEEK_SET: @@ -209,8 +210,6 @@ fhandler_virtual::open (path_conv *, int flags, mode_t mode) set_flags ((flags & ~O_TEXT) | O_BINARY); - set_nohandle (true); - return 1; } @@ -220,7 +219,8 @@ fhandler_virtual::exists () return 0; } -void +bool fhandler_virtual::fill_filebuf () { + return true; } diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index f5516aa60..c7dfbbefa 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -28,6 +28,7 @@ details. */ #include #include #include +#include #include "cygerrno.h" #include "security.h" #include "fhandler.h" @@ -1301,6 +1302,174 @@ get_file_attribute (int use_ntsec, const char *file, return res > 0 ? 0 : -1; } +static int +get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribute, + __uid32_t *uidret, __gid32_t *gidret) +{ + if (!wincap.has_security ()) + return 0; + + PSECURITY_DESCRIPTOR psd = NULL; + PSID owner_sid; + PSID group_sid; + PACL acl; + + if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type, + DACL_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION, + &owner_sid, + &group_sid, + &acl, + NULL, + &psd)) + { + __seterrno (); + debug_printf ("GetSecurityInfo %E"); + return -1; + } + + __uid32_t uid = cygsid (owner_sid).get_uid (); + __gid32_t gid = cygsid (group_sid).get_gid (); + if (uidret) + *uidret = uid; + if (gidret) + *gidret = gid; + + if (!attribute) + { + syscall_printf ("uid %d, gid %d", uid, gid); + LocalFree (psd); + return 0; + } + + BOOL grp_member = is_grp_member (uid, gid); + + if (!acl) + { + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + syscall_printf ("No ACL = %x, uid %d, gid %d", + *attribute, uid, gid); + LocalFree (psd); + return 0; + } + + ACCESS_ALLOWED_ACE *ace; + int allow = 0; + int deny = 0; + int *flags, *anti; + + for (DWORD i = 0; i < acl->AceCount; ++i) + { + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + if (ace->Header.AceFlags & INHERIT_ONLY_ACE) + continue; + switch (ace->Header.AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + flags = &allow; + anti = &deny; + break; + case ACCESS_DENIED_ACE_TYPE: + flags = &deny; + anti = &allow; + break; + default: + continue; + } + + cygsid ace_sid ((PSID) &ace->SidStart); + if (owner_sid && ace_sid == owner_sid) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRUSR; + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWUSR; + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXUSR; + } + else if (group_sid && ace_sid == group_sid) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRGRP + | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWGRP + | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXGRP + | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + else if (ace_sid == well_known_world_sid) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IROTH + | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) + | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWOTH + | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) + | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + { + *flags |= S_IXOTH + | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) + | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + if ((*attribute & S_IFDIR) && + (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD)) + == (FILE_WRITE_DATA | FILE_EXECUTE)) + *flags |= S_ISVTX; + } + else if (ace_sid == well_known_null_sid) + { + /* Read SUID, SGID and VTX bits from NULL ACE. */ + if (ace->Mask & FILE_READ_DATA) + *flags |= S_ISVTX; + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_ISGID; + if (ace->Mask & FILE_APPEND_DATA) + *flags |= S_ISUID; + } + } + *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); + *attribute |= allow; + *attribute &= ~deny; + + LocalFree (psd); + + syscall_printf ("%x, uid %d, gid %d", *attribute, uid, gid); + return 0; +} + +int +get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, + int *attribute, __uid32_t *uidret, __gid32_t *gidret) +{ + if (allow_ntsec) + { + int res = get_nt_object_attribute (handle, object_type, attribute, uidret, gidret); + if (attribute && (*attribute & S_IFLNK) == S_IFLNK) + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + return res; + } + + if (uidret) + *uidret = getuid32 (); + if (gidret) + *gidret = getgid32 (); + + if (!attribute) + return 0; + + /* symlinks are everything for everyone!*/ + if ((*attribute & S_IFLNK) == S_IFLNK) + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + return 0; +} + BOOL add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit) diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 88aa5fdac..36ae57705 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -8,6 +8,7 @@ This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ +#include #define DONT_INHERIT (0) #define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) #define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) @@ -169,6 +170,8 @@ int __stdcall get_file_attribute (int, const char *, int *, __uid32_t * = NULL, __gid32_t * = NULL); int __stdcall set_file_attribute (int, const char *, int); int __stdcall set_file_attribute (int, const char *, __uid32_t, __gid32_t, int); +int __stdcall get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *, + __uid32_t * = NULL, __gid32_t * = NULL); LONG __stdcall read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size); LONG __stdcall write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size); BOOL __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);