diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 18fc01886..7ee5de3ec 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,23 @@ +2004-04-14 Corinna Vinschen + + * fhandler.cc (fhandler_base::open): Accomodate query_write_control + query_state. + (fhandler_base::fchown): New method. + * fhandler.h: Declare fchown method in fhandler_base, + fhandler_disk_file and fhandler_virtual. + (enum query_state): Add query_write_control. + * fhandler_disk_file.cc (fhandler_disk_file::fchmod): Set query_state + to query_write_control. Only remove FILE_ATTRIBUTE_READONLY if not + setting security descriptor. + (fhandler_disk_file::fchown): New method. + * fhandler_virtual.cc (fhandler_virtual::fchown): New method. + * sec_acl.cc (setacl): Call write_sd with additional handle attribute. + * security.cc (write_sd): Take handle argument. Only request owner + if getting SE_RESTORE_NAME privilege failed. Only open file if + NtSetSecurityObject failed or handle is NULL. + (set_nt_attribute): Call write_sd with additional handle attribute. + * security.h (write_sd): Declare with additional handle argument. + 2004-04-14 Corinna Vinschen * autoload.cc (NtSetSecurityObject): Add. diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 540fca58c..b93102dd1 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -443,7 +443,18 @@ fhandler_base::open (int flags, mode_t mode) } if (query_open ()) - access = (query_open () == query_read_control ? READ_CONTROL : 0); + switch (query_open ()) + { + case query_null_access: + access = 0; + break; + case query_read_control: + access = READ_CONTROL; + break; + case query_write_control: + access = READ_CONTROL | WRITE_OWNER | WRITE_DAC; + break; + } else if (get_major () == DEV_TAPE_MAJOR) access = GENERIC_READ | GENERIC_WRITE; else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY) @@ -1411,3 +1422,10 @@ fhandler_base::fchmod (mode_t mode) /* By default, just succeeds. */ return 0; } + +int +fhandler_base::fchown (__uid32_t uid, __gid32_t gid) +{ + /* By default, just succeeds. */ + return 0; +} diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index ece8d4984..0ee198c54 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -62,8 +62,9 @@ enum bg_check_types enum query_state { no_query = 0, - query_read_control = 1, - query_null_access = 2 + query_null_access = 1, + query_read_control = 2, + query_write_control = 3 }; class fhandler_base @@ -243,6 +244,7 @@ class fhandler_base 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 __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); virtual int ioctl (unsigned int cmd, void *); virtual int fcntl (int cmd, void *); virtual char const *ttyname () { return get_name (); } @@ -568,6 +570,7 @@ class fhandler_disk_file: public fhandler_base bool isdevice () { return false; } int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); + int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); 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); @@ -1101,6 +1104,7 @@ class fhandler_virtual : public fhandler_base int close (void); int __stdcall fstat (struct stat *buf) __attribute__ ((regparm (2))); int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); + int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); 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 28f930617..f649d4dbd 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -377,14 +377,18 @@ fhandler_disk_file::fchmod (mode_t mode) if (pc.is_fs_special ()) return chmod_device (pc, mode); - query_open (query_read_control); - if (!get_io_handle () && !(oret = open_fs (O_BINARY, 0))) - return -1; + if (!get_io_handle ()) + { + query_open (query_write_control); + if (!(oret = open_fs (O_BINARY, 0))) + return -1; + } - SetFileAttributes (get_win32_name (), (DWORD) pc & ~FILE_ATTRIBUTE_READONLY); + if (!allow_ntsec && allow_ntea) /* Not necessary when manipulating SD. */ + SetFileAttributes (pc, (DWORD) pc & ~FILE_ATTRIBUTE_READONLY); if (pc.isdir ()) mode |= S_IFDIR; - if (!set_file_attribute (pc.has_acls (), get_io_handle (), get_win32_name (), + if (!set_file_attribute (pc.has_acls (), get_io_handle (), pc, ILLEGAL_UID, ILLEGAL_GID, mode) && allow_ntsec) res = 0; @@ -410,6 +414,37 @@ fhandler_disk_file::fchmod (mode_t mode) return res; } +int __stdcall +fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid) +{ + int oret = 0; + if (!get_io_handle ()) + { + query_open (query_write_control); + if (!(oret = open_fs (O_BINARY, 0))) + return -1; + } + + mode_t attrib = 0; + if (pc.isdir ()) + attrib |= S_IFDIR; + int res = get_file_attribute (pc.has_acls (), get_io_handle (), pc, &attrib); + if (!res) + res = set_file_attribute (pc.has_acls (), get_io_handle (), pc, + uid, gid, attrib); + if (res && (!pc.has_acls () || !allow_ntsec)) + { + /* fake - if not supported, pretend we're like win95 + where it just works */ + res = 0; + } + + if (oret) + close_fs (); + + return res; +} + fhandler_disk_file::fhandler_disk_file () : fhandler_base () { diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index 65be71b23..16b83923e 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -234,3 +234,11 @@ fhandler_virtual::fchmod (mode_t mode) set_errno (EPERM); return -1; } + +int +fhandler_virtual::fchown (__uid32_t uid, __gid32_t gid) +{ + /* Same as on Linux. */ + set_errno (EPERM); + return -1; +} diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc index dc2473e9e..a8dbe2f90 100644 --- a/winsup/cygwin/sec_acl.cc +++ b/winsup/cygwin/sec_acl.cc @@ -223,7 +223,7 @@ setacl (const char *file, int nentries, __aclent32_t *aclbufp) return -1; } debug_printf ("Created SD-Size: %d", sd_ret.size ()); - return write_sd (file, sd_ret); + return write_sd (NULL, file, sd_ret); } /* Temporary access denied bits */ diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index c932c2441..0915a77e6 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1117,16 +1117,8 @@ read_sd (const char *file, security_descriptor &sd) } LONG -write_sd (const char *file, security_descriptor &sd) +write_sd (HANDLE fh, const char *file, security_descriptor &sd) { - BOOL dummy; - cygpsid owner; - - if (!GetSecurityDescriptorOwner (sd, (PSID *) &owner, &dummy)) - { - __seterrno (); - return -1; - } /* Try turning privilege on, may not have WRITE_OWNER or WRITE_DAC access. Must have privilege to set different owner, else BackupWrite misbehaves */ static int NO_COPY saved_res; /* 0: never, 1: failed, 2 & 3: OK */ @@ -1140,29 +1132,42 @@ write_sd (const char *file, security_descriptor &sd) } else res = saved_res; - if (res == 1 && owner != cygheap->user.sid ()) + if (res == 1) { - set_errno (EPERM); - return -1; + BOOL dummy; + cygpsid owner; + + if (!GetSecurityDescriptorOwner (sd, (PSID *) &owner, &dummy)) + { + __seterrno (); + return -1; + } + if (owner != cygheap->user.sid ()) + { + set_errno (EPERM); + return -1; + } } - HANDLE fh; - if ((fh = CreateFile (file, - WRITE_OWNER | WRITE_DAC, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, - NULL)) == INVALID_HANDLE_VALUE) + NTSTATUS ret; + int retry = 0; + for (; retry < 2; ++retry) { - __seterrno (); - return -1; + if (retry && (fh = CreateFile (file, WRITE_OWNER | WRITE_DAC, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL + | FILE_FLAG_BACKUP_SEMANTICS, + NULL)) == INVALID_HANDLE_VALUE) + break; + if (fh && (ret = NtSetSecurityObject (fh, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd)) == STATUS_SUCCESS) + break; } - NTSTATUS ret = NtSetSecurityObject (fh, - DACL_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | OWNER_SECURITY_INFORMATION, - sd); - CloseHandle (fh); + if (retry && fh != INVALID_HANDLE_VALUE) + CloseHandle (fh); if (ret != STATUS_SUCCESS) { __seterrno_from_win_error (RtlNtStatusToDosError (ret)); @@ -1802,7 +1807,7 @@ set_nt_attribute (HANDLE handle, const char *file, if (!alloc_sd (uid, gid, attribute, sd)) return -1; - return write_sd (file, sd); + return write_sd (handle, file, sd); } int diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 2fb7c8085..e81a8d8ae 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -256,7 +256,7 @@ int __stdcall set_file_attribute (bool, HANDLE, const char *, __uid32_t, __gid32 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); -LONG __stdcall write_sd (const char *file, security_descriptor &sd); +LONG __stdcall write_sd (HANDLE fh, const char *file, security_descriptor &sd); bool __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); bool __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); int __stdcall check_file_access (const char *, int);