From 854c870051c471f7f8d8dcf36e1ee3263eb9218f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 13 Apr 2004 20:36:58 +0000 Subject: [PATCH] * dir.cc (mkdir): Call set_file_attribute with additional handle argument. * fhandler.cc (fhandler_base::fchmod): New method. * fhandler.h: Declare fchmod method in fhandler_base, fhandler_disk_file and fhandler_virtual. * fhandler_disk_file.cc (fhandler_disk_file::fchmod): New method. (fhandler_base::open_fs): Call set_file_attribute with additional handle argument. * fhandler_virtual.cc (fhandler_virtual::fchmod): New method. * path.cc (symlink_worker): Call set_file_attribute with additional handle argument. * security.cc (get_nt_object_security): New function. (get_nt_object_attribute): Call get_nt_object_security. (set_nt_attribute): Add handle argument. Call get_nt_object_security first, read_sd only if that fails. (set_file_attribute): Add handle argument. * security.h (set_file_attribute): Declare with additional handle argument. * syscalls.cc (stat_suffixes): Move to beginning of file. (chown_worker): Call set_file_attribute with additional handle argument. (chmod): Reorganize to call fhandler's fchmod method eventually. (fchmod): Ditto. --- winsup/cygwin/ChangeLog | 25 +++++++++ winsup/cygwin/dir.cc | 2 +- winsup/cygwin/fhandler.cc | 7 +++ winsup/cygwin/fhandler.h | 3 + winsup/cygwin/fhandler_disk_file.cc | 44 ++++++++++++++- winsup/cygwin/fhandler_virtual.cc | 8 +++ winsup/cygwin/path.cc | 2 +- winsup/cygwin/security.cc | 72 ++++++++++++++---------- winsup/cygwin/security.h | 4 +- winsup/cygwin/syscalls.cc | 87 ++++++----------------------- 10 files changed, 148 insertions(+), 106 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 35bde4d68..5eb32ff4a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,28 @@ +2004-04-13 Corinna Vinschen + + * dir.cc (mkdir): Call set_file_attribute with additional handle + argument. + * fhandler.cc (fhandler_base::fchmod): New method. + * fhandler.h: Declare fchmod method in fhandler_base, + fhandler_disk_file and fhandler_virtual. + * fhandler_disk_file.cc (fhandler_disk_file::fchmod): New method. + (fhandler_base::open_fs): Call set_file_attribute with additional + handle argument. + * fhandler_virtual.cc (fhandler_virtual::fchmod): New method. + * path.cc (symlink_worker): Call set_file_attribute with additional + handle argument. + * security.cc (get_nt_object_security): New function. + (get_nt_object_attribute): Call get_nt_object_security. + (set_nt_attribute): Add handle argument. Call get_nt_object_security + first, read_sd only if that fails. + (set_file_attribute): Add handle argument. + * security.h (set_file_attribute): Declare with additional handle + argument. + * syscalls.cc (stat_suffixes): Move to beginning of file. + (chown_worker): Call set_file_attribute with additional handle argument. + (chmod): Reorganize to call fhandler's fchmod method eventually. + (fchmod): Ditto. + 2004-04-13 Corinna Vinschen * autoload.cc (NtQuerySecurityObject): Add. diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 303326e9d..4fc1932da 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -284,7 +284,7 @@ mkdir (const char *dir, mode_t mode) if (CreateDirectoryA (real_dir.get_win32 (), &sa)) { if (!allow_ntsec && allow_ntea) - set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (), + set_file_attribute (real_dir.has_acls (), NULL, real_dir.get_win32 (), S_IFDIR | ((mode & 07777) & ~cygheap->umask)); #ifdef HIDDEN_DOT_FILES char *c = strrchr (real_dir.get_win32 (), '\\'); diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index a005e6109..540fca58c 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1404,3 +1404,10 @@ fhandler_base::closedir (DIR *) set_errno (ENOTDIR); return -1; } + +int +fhandler_base::fchmod (mode_t mode) +{ + /* By default, just succeeds. */ + return 0; +} diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index b8b4ecf6a..ece8d4984 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -242,6 +242,7 @@ class fhandler_base __attribute__ ((regparm (3))); int __stdcall fstat_by_handle (struct __stat64 *buf) __attribute__ ((regparm (2))); int __stdcall fstat_by_name (struct __stat64 *buf) __attribute__ ((regparm (2))); + virtual int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); virtual int ioctl (unsigned int cmd, void *); virtual int fcntl (int cmd, void *); virtual char const *ttyname () { return get_name (); } @@ -566,6 +567,7 @@ class fhandler_disk_file: public fhandler_base int lock (int, struct __flock64 *); bool isdevice () { return false; } int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); + int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, _off64_t off); int munmap (HANDLE h, caddr_t addr, size_t len); @@ -1098,6 +1100,7 @@ class fhandler_virtual : public fhandler_base int open (int flags, mode_t mode = 0); int close (void); int __stdcall fstat (struct stat *buf) __attribute__ ((regparm (2))); + int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); virtual bool fill_filebuf (); void fixup_after_exec (); }; diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 62c4605a2..587f32314 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -366,6 +366,48 @@ fhandler_disk_file::fstat (struct __stat64 *buf) return fstat_fs (buf); } +int __stdcall +fhandler_disk_file::fchmod (mode_t mode) +{ + extern int chmod_device (path_conv& pc, mode_t mode); + int res = -1; + int oret = 0; + + if (pc.is_fs_special ()) + return chmod_device (pc, mode); + + if (!get_io_handle () && !(oret = open_fs (O_RDONLY | O_BINARY, 0))) + return -1; + + SetFileAttributes (get_win32_name (), (DWORD) pc & ~FILE_ATTRIBUTE_READONLY); + if (pc.isdir ()) + mode |= S_IFDIR; + if (!set_file_attribute (pc.has_acls (), get_io_handle (), get_win32_name (), + ILLEGAL_UID, ILLEGAL_GID, mode) + && allow_ntsec) + res = 0; + + /* if the mode we want has any write bits set, we can't be read only. */ + if (mode & (S_IWUSR | S_IWGRP | S_IWOTH)) + (DWORD) pc &= ~FILE_ATTRIBUTE_READONLY; + else + (DWORD) pc |= FILE_ATTRIBUTE_READONLY; + + if (!pc.is_lnk_symlink () && S_ISLNK (mode) || S_ISSOCK (mode)) + (DWORD) pc |= FILE_ATTRIBUTE_SYSTEM; + + if (!SetFileAttributes (pc, pc)) + __seterrno (); + else if (!allow_ntsec) + /* Correct NTFS security attributes have higher priority */ + res = 0; + + if (oret) + close_fs (); + + return res; +} + fhandler_disk_file::fhandler_disk_file () : fhandler_base () { @@ -411,7 +453,7 @@ fhandler_base::open_fs (int flags, mode_t mode) if (flags & O_CREAT && GetLastError () != ERROR_ALREADY_EXISTS && !allow_ntsec && allow_ntea) - set_file_attribute (has_acls (), get_win32_name (), mode); + set_file_attribute (has_acls (), NULL, get_win32_name (), mode); set_fs_flags (pc.fs_flags ()); diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index 94da2c1b8..65be71b23 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -226,3 +226,11 @@ fhandler_virtual::fill_filebuf () { return true; } + +int +fhandler_virtual::fchmod (mode_t mode) +{ + /* Same as on Linux. */ + set_errno (EPERM); + return -1; +} diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 91945e391..08e019915 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2648,7 +2648,7 @@ symlink_worker (const char *topath, const char *frompath, bool use_winsym, { CloseHandle (h); if (!allow_ntsec && allow_ntea) - set_file_attribute (win32_path.has_acls (), + set_file_attribute (win32_path.has_acls (), NULL, win32_path.get_win32 (), S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 8420f857b..8abf40564 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1367,6 +1367,37 @@ get_nt_attribute (const char *file, mode_t *attribute, get_info_from_sd (sd, attribute, uidret, gidret); } +static int +get_nt_object_security (HANDLE handle, SE_OBJECT_TYPE object_type, + security_descriptor &sd_ret) +{ + NTSTATUS ret; + ULONG len = 0; + ret = NtQuerySecurityObject (handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, len, &len); + if (ret == STATUS_BUFFER_TOO_SMALL) + { + if (!sd_ret.malloc (len)) + set_errno (ENOMEM); + else + ret = NtQuerySecurityObject (handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, len, &len); + } + if (ret != STATUS_SUCCESS) + { + sd_ret.free (); + __seterrno_from_win_error (RtlNtStatusToDosError (ret)); + return -1; + } + return 0; +} + static int get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, mode_t *attribute, __uid32_t *uidret, @@ -1375,34 +1406,14 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, security_descriptor sd; PSECURITY_DESCRIPTOR psd = NULL; - NTSTATUS ret; - ULONG len = 0; - ret = NtQuerySecurityObject (handle, - DACL_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | OWNER_SECURITY_INFORMATION, - sd, len, &len); - if (ret == STATUS_BUFFER_TOO_SMALL) + if (get_nt_object_security (handle, object_type, sd)) { - if (!sd.malloc (len)) - set_errno (ENOMEM); - else - ret = NtQuerySecurityObject (handle, - DACL_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | OWNER_SECURITY_INFORMATION, - sd, len, &len); - } - if (ret != STATUS_SUCCESS) - { - __seterrno_from_win_error (RtlNtStatusToDosError (ret)); if (object_type == SE_FILE_OBJECT) - return -1; + return -1; } else psd = sd; get_info_from_sd (psd, attribute, uidret, gidret); - return 0; } @@ -1805,16 +1816,16 @@ set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, } static int -set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid, - int attribute) +set_nt_attribute (HANDLE handle, const char *file, + __uid32_t uid, __gid32_t gid, int attribute) { if (!wincap.has_security ()) return 0; security_descriptor sd; - int ret; - if ((ret = read_sd (file, sd)) <= 0) + if (get_nt_object_security (handle, SE_FILE_OBJECT, sd) + && read_sd (file, sd) <= 0) { debug_printf ("read_sd %E"); return -1; @@ -1827,13 +1838,13 @@ set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid, } int -set_file_attribute (int use_ntsec, const char *file, +set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, __uid32_t uid, __gid32_t gid, int attribute) { int ret = 0; if (use_ntsec && allow_ntsec) - ret = set_nt_attribute (file, uid, gid, attribute); + ret = set_nt_attribute (handle, file, uid, gid, attribute); else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute, sizeof (attribute))) { @@ -1846,9 +1857,10 @@ set_file_attribute (int use_ntsec, const char *file, } int -set_file_attribute (int use_ntsec, const char *file, int attribute) +set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, + int attribute) { - return set_file_attribute (use_ntsec, file, + return set_file_attribute (use_ntsec, handle, file, myself->uid, myself->gid, attribute); } diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index d9c90cd79..2fb7c8085 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -251,8 +251,8 @@ extern bool allow_smbntsec; int __stdcall set_process_privileges (); int __stdcall get_file_attribute (int, HANDLE, const char *, mode_t *, __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 set_file_attribute (bool, HANDLE, const char *, int); +int __stdcall set_file_attribute (bool, HANDLE, const char *, __uid32_t, __gid32_t, int); int __stdcall get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, mode_t *, __uid32_t * = NULL, __gid32_t * = NULL); LONG __stdcall read_sd (const char *file, security_descriptor &sd); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 11c47fd02..ed8b902d6 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -71,6 +71,13 @@ details. */ #undef _lseek64 #undef _fstat64 +suffix_info stat_suffixes[] = +{ + suffix_info ("", 1), + suffix_info (".exe", 1), + suffix_info (NULL) +}; + SYSTEM_INFO system_info; static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t, @@ -849,8 +856,8 @@ chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid) res = get_file_attribute (win32_path.has_acls (), NULL, win32_path.get_win32 (), &attrib); if (!res) - res = set_file_attribute (win32_path.has_acls (), win32_path, uid, - gid, attrib); + res = set_file_attribute (win32_path.has_acls (), NULL, win32_path, + uid, gid, attrib); if (res != 0 && (!win32_path.has_acls () || !allow_ntsec)) { /* fake - if not supported, pretend we're like win95 @@ -943,60 +950,16 @@ extern "C" int chmod (const char *path, mode_t mode) { int res = -1; - - path_conv win32_path (path); - - if (win32_path.error) + fhandler_base *fh = build_fh_name (path, NULL, PC_SYM_FOLLOW | PC_FULL, + stat_suffixes); + if (fh->error ()) { - set_errno (win32_path.error); - goto done; + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); } - - /* FIXME: This makes chmod on a device succeed always. Someday we'll want - to actually allow chmod to work properly on devices. */ - if (win32_path.is_auto_device ()) - { - res = 0; - goto done; - } - if (win32_path.is_fs_special ()) - { - res = chmod_device (win32_path, mode); - goto done; - } - - if (!win32_path.exists ()) - __seterrno (); else - { - /* temporary erase read only bit, to be able to set file security */ - SetFileAttributes (win32_path, (DWORD) win32_path & ~FILE_ATTRIBUTE_READONLY); + res = fh->fchmod (mode); - if (win32_path.isdir ()) - mode |= S_IFDIR; - if (!set_file_attribute (win32_path.has_acls (), win32_path, - ILLEGAL_UID, ILLEGAL_GID, mode) - && allow_ntsec) - res = 0; - - /* if the mode we want has any write bits set, we can't - be read only. */ - if (mode & (S_IWUSR | S_IWGRP | S_IWOTH)) - (DWORD) win32_path &= ~FILE_ATTRIBUTE_READONLY; - else - (DWORD) win32_path |= FILE_ATTRIBUTE_READONLY; - - if (!win32_path.is_lnk_symlink () && S_ISLNK (mode) || S_ISSOCK (mode)) - (DWORD) win32_path |= FILE_ATTRIBUTE_SYSTEM; - - if (!SetFileAttributes (win32_path, win32_path)) - __seterrno (); - else if (!allow_ntsec) - /* Correct NTFS security attributes have higher priority */ - res = 0; - } - -done: syscall_printf ("%d = chmod (%s, %p)", res, path, mode); return res; } @@ -1013,18 +976,7 @@ fchmod (int fd, mode_t mode) return -1; } - const char *path = cfd->get_name (); - - if (path == NULL) - { - syscall_printf ("-1 = fchmod (%d, 0%o) (no name)", fd, mode); - set_errno (ENOSYS); - return -1; - } - - syscall_printf ("fchmod (%d, 0%o): calling chmod (%s, 0%o)", - fd, mode, path, mode); - return chmod (path, mode); + return cfd->fchmod (mode); } static void @@ -1129,13 +1081,6 @@ sync () { } -suffix_info stat_suffixes[] = -{ - suffix_info ("", 1), - suffix_info (".exe", 1), - suffix_info (NULL) -}; - /* Cygwin internal */ static int __stdcall stat_worker (const char *name, struct __stat64 *buf, int nofollow)