From cf762b08cfb010d9d63e4ca44658c80bdf6ed8cb Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 21 Feb 2003 14:29:18 +0000 Subject: [PATCH] * dtable.cc (dtable::build_fhandler_from_name): Set some fhandler data on sockets to evaluate AF_LOCAL sockets correctly. (dtable::build_fhandler): Set unit number on sockets. * fhandler.h (fhandler_socket): Add unit number. (fhandler_socket::get_unit): New method. * fhandler_socket.cc (fhandler_socket::fhandler_socket): Set unit number. (fhandler_socket::fstat): Reorganize to return more Linux-like values. * net.cc: include ctype.h. (fdsock): Set unit number when building fhandler. * path.cc (path_conv::check): Set device type to FH_SOCKET if file is a AF_UNIX socket. (get_devn): Evaluate unit for virtual socket devices. (win32_device_name): Set windows path for sockets to unix_path with just backslashes to keep the different names. * syscalls.cc (fstat64): Don't override st_ino, st_dev and st_rdev for sockets. (stat_worker): Ditto. From Pierre Humblet: * autoload.cc (AccessCheck): Add. (DuplicateToken): Add. * security.h (check_file_access): Declare. * syscalls.cc (access): Convert path to Windows, check existence and readonly attribute. Call check_file_access instead of acl_access. * security.cc (check_file_access): Create. * sec_acl (acl_access): Delete. --- winsup/cygwin/ChangeLog | 32 ++++++++++++++++ winsup/cygwin/autoload.cc | 2 + winsup/cygwin/dtable.cc | 12 ++++-- winsup/cygwin/fhandler.h | 4 +- winsup/cygwin/fhandler_socket.cc | 47 +++++++++++++++++++++--- winsup/cygwin/net.cc | 6 ++- winsup/cygwin/path.cc | 13 +++++-- winsup/cygwin/sec_acl.cc | 63 -------------------------------- winsup/cygwin/security.cc | 51 ++++++++++++++++++++++++++ winsup/cygwin/security.h | 1 + winsup/cygwin/syscalls.cc | 34 +++++++++++++---- 11 files changed, 180 insertions(+), 85 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b05cdc41b..ab1c240cb 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,35 @@ +2003-02-21 Corinna Vinschen + + * dtable.cc (dtable::build_fhandler_from_name): Set some fhandler + data on sockets to evaluate AF_LOCAL sockets correctly. + (dtable::build_fhandler): Set unit number on sockets. + * fhandler.h (fhandler_socket): Add unit number. + (fhandler_socket::get_unit): New method. + * fhandler_socket.cc (fhandler_socket::fhandler_socket): Set unit + number. + (fhandler_socket::fstat): Reorganize to return more Linux-like + values. + * net.cc: include ctype.h. + (fdsock): Set unit number when building fhandler. + * path.cc (path_conv::check): Set device type to FH_SOCKET if file + is a AF_UNIX socket. + (get_devn): Evaluate unit for virtual socket devices. + (win32_device_name): Set windows path for sockets to unix_path with + just backslashes to keep the different names. + * syscalls.cc (fstat64): Don't override st_ino, st_dev and st_rdev + for sockets. + (stat_worker): Ditto. + +2003-02-21 Pierre Humblet + + * autoload.cc (AccessCheck): Add. + (DuplicateToken): Add. + * security.h (check_file_access): Declare. + * syscalls.cc (access): Convert path to Windows, check existence + and readonly attribute. Call check_file_access instead of acl_access. + * security.cc (check_file_access): Create. + * sec_acl (acl_access): Delete. + 2003-02-19 Christopher Faylor * fhandler.cc (fhandler_base::open): Move some filesystem specific diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index d071ab1d2..b29c9d269 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -307,6 +307,7 @@ wsock_init () LoadDLLprime (wsock32, wsock_init) LoadDLLprime (ws2_32, wsock_init) +LoadDLLfunc (AccessCheck, 32, advapi32) LoadDLLfunc (AddAccessAllowedAce, 16, advapi32) LoadDLLfunc (AddAccessDeniedAce, 16, advapi32) LoadDLLfunc (AddAce, 20, advapi32) @@ -318,6 +319,7 @@ LoadDLLfuncEx (CryptAcquireContextA, 20, advapi32, 1) LoadDLLfuncEx (CryptGenRandom, 12, advapi32, 1) LoadDLLfuncEx (CryptReleaseContext, 8, advapi32, 1) LoadDLLfunc (DeregisterEventSource, 4, advapi32) +LoadDLLfunc (DuplicateToken, 12, advapi32) LoadDLLfuncEx (DuplicateTokenEx, 24, advapi32, 1) LoadDLLfunc (EqualSid, 8, advapi32) LoadDLLfunc (GetAce, 12, advapi32) diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 03490b602..73af42e20 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -299,9 +299,15 @@ dtable::build_fhandler_from_name (int fd, const char *name, HANDLE handle, if (!pc.exists () && handle) pc.fillin (handle); - fhandler_base *fh = build_fhandler (fd, pc.get_devn (), - pc.return_and_clear_normalized_path (), + char *posix_path = pc.return_and_clear_normalized_path (); + fhandler_base *fh = build_fhandler (fd, pc.get_devn (), posix_path, pc, pc.get_unitn ()); + if (pc.issocket ()) /* Only true for files pretending an AF_LOCAL socket. */ + { + fhandler_socket * fhs = (fhandler_socket *) fh; + fhs->set_addr_family (AF_LOCAL); + fhs->set_sun_path (posix_path); + } return fh; } @@ -352,7 +358,7 @@ dtable::build_fhandler (int fd, DWORD dev, char *unix_name, fh = cnew (fhandler_pipe) (dev); break; case FH_SOCKET: - if ((fh = cnew (fhandler_socket) ())) + if ((fh = cnew (fhandler_socket) (unit))) inc_need_fixup_before (); break; case FH_DISK: diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 8840cb85f..cc6ae7c20 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -385,12 +385,14 @@ class fhandler_socket: public fhandler_base struct _WSAPROTOCOL_INFOA *prot_info_ptr; char *sun_path; int had_connect_or_listen; + int unit; public: - fhandler_socket (); + fhandler_socket (int unit); ~fhandler_socket (); int get_socket () { return (int) get_handle(); } fhandler_socket * is_socket () { return this; } + int get_unit () { return unit; } bool saw_shutdown_read () const {return FHISSETF (SHUTRD);} bool saw_shutdown_write () const {return FHISSETF (SHUTWR);} diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 6c867f927..b10e28a8c 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -94,8 +94,8 @@ get_inet_addr (const struct sockaddr *in, int inlen, /**********************************************************************/ /* fhandler_socket */ -fhandler_socket::fhandler_socket () - : fhandler_base (FH_SOCKET), sun_path (NULL) +fhandler_socket::fhandler_socket (int nunit) + : fhandler_base (FH_SOCKET), unit (nunit), sun_path (NULL) { set_need_fork_fixup (); prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF, @@ -309,12 +309,47 @@ fhandler_socket::dup (fhandler_base *child) int __stdcall fhandler_socket::fstat (struct __stat64 *buf, path_conv *pc) { - int res = fhandler_base::fstat (buf, pc); + int res; + if (get_addr_family () == AF_LOCAL && get_sun_path ()) + { + path_conv spc (get_sun_path (), + PC_SYM_NOFOLLOW | PC_NULLEMPTY | PC_FULL | PC_POSIX, + NULL); + fhandler_base *fh = cygheap->fdtab.build_fhandler (-1, FH_DISK, + get_sun_path (), + spc, 0); + if (fh) + { + res = fh->fstat (buf, &spc); + /* Faking Linux like values on top of the file specific values. */ + if (get_socket_type ()) /* fstat() */ + { + buf->st_dev = 0; + buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO; + buf->st_ino = (ino_t) get_handle (); + } + buf->st_rdev = buf->st_size = buf->st_blocks = 0; + return res; + } + } + + res = fhandler_base::fstat (buf, pc); if (!res) { - buf->st_mode &= ~_IFMT; - buf->st_mode |= _IFSOCK; - buf->st_ino = (ino_t) get_handle (); + if (get_socket_type ()) /* fstat */ + { + buf->st_ino = (ino_t) get_handle (); + buf->st_mode &= ~S_IFMT; + buf->st_mode |= S_IFSOCK; + } + else + { + path_conv spc ("/dev", PC_SYM_NOFOLLOW | PC_NULLEMPTY, NULL); + buf->st_dev = spc.volser (); + buf->st_ino = (ino_t) get_namehash (); + buf->st_mode &= ~S_IRWXO; + buf->st_rdev = (get_device () << 16) | get_unit (); + } } return res; } diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 6bfec1fa9..cfc716c68 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -14,6 +14,7 @@ details. */ #include "winsup.h" #include +#include #include #include #include @@ -521,8 +522,9 @@ fdsock (int &fd, const char *name, SOCKET soc) else debug_printf ("not setting socket inheritance since winsock2_active %d", winsock2_active); - fhandler_socket *fh = - (fhandler_socket *) cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name); + fhandler_socket *fh = (fhandler_socket *) + cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name, NULL, + tolower (name[5]) - 'a'); if (!fh) return NULL; fh->set_io_handle ((HANDLE) soc); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d75f8a0c5..dea1d372f 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -799,10 +799,8 @@ out: set_has_buggy_open (strcmp (fs.name, "SUNWNFS") == 0); } } -#if 0 if (issocket ()) devn = FH_SOCKET; -#endif if (!(opt & PC_FULL)) { @@ -954,7 +952,10 @@ get_devn (const char *name, int &unit) devn = FH_PIPEW; else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket") || deveq ("dgsocket")) - devn = FH_SOCKET; + { + devn = FH_SOCKET; + unit = tolower (*name) - 'a'; + } return devn; } @@ -1118,6 +1119,12 @@ win32_device_name (const char *src_path, char *win32_path, return false; switch (devn) { + case FH_SOCKET: + char *c; + strcpy (win32_path, src_path); + while (c = strchr (win32_path, '/')) + *c = '\\'; + break; case FH_RANDOM: __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u"); break; diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc index febda4fb2..3a9f08b55 100644 --- a/winsup/cygwin/sec_acl.cc +++ b/winsup/cygwin/sec_acl.cc @@ -413,69 +413,6 @@ getacl (const char *file, DWORD attr, int nentries, __aclent32_t *aclbufp) return pos; } -int -acl_access (const char *path, int flags) -{ - __aclent32_t acls[MAX_ACL_ENTRIES]; - int cnt; - - if ((cnt = acl32 (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1) - return -1; - - /* Only check existence. */ - if (!(flags & (R_OK | W_OK | X_OK))) - return 0; - - for (int i = 0; i < cnt; ++i) - { - switch (acls[i].a_type) - { - case USER_OBJ: - case USER: - if (acls[i].a_id != myself->uid) - { - /* - * Check if user is a NT group: - * Take SID from passwd, search SID in token groups - */ - cygsid owner; - struct passwd *pw; - - if ((pw = internal_getpwuid (acls[i].a_id)) != NULL - && owner.getfrompw (pw) - && internal_getgroups (0, NULL, &owner) > 0) - break; - continue; - } - break; - case GROUP_OBJ: - case GROUP: - if (acls[i].a_id != myself->gid) - { - cygsid group; - struct __group32 *gr = NULL; - - if ((gr = internal_getgrgid (acls[i].a_id)) != NULL - && group.getfromgr (gr) - && internal_getgroups (0, NULL, &group) > 0) - break; - continue; - } - break; - case OTHER_OBJ: - break; - default: - continue; - } - if ((!(flags & R_OK) || (acls[i].a_perm & S_IROTH)) - && (!(flags & W_OK) || (acls[i].a_perm & S_IWOTH)) - && (!(flags & X_OK) || (acls[i].a_perm & S_IXOTH))) - return 0; - } - set_errno (EACCES); - return -1; -} - static int acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp, diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 35ac5cfac..847aa4afb 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1918,3 +1918,54 @@ set_file_attribute (int use_ntsec, const char *file, int attribute) return set_file_attribute (use_ntsec, file, myself->uid, myself->gid, attribute); } + +int +check_file_access (const char *fn, int flags) +{ + int ret = -1; + char sd_buf[4096]; + DWORD sd_size = sizeof sd_buf; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + HANDLE hToken, hIToken; + BOOL status; + char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)]; + DWORD desired = 0, granted, plength = sizeof pbuf; + static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS }; + if (read_sd (fn, psd, &sd_size) <= 0) + goto done; + + if (cygheap->user.issetuid ()) + hToken = cygheap->user.token; + else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken)) + { + __seterrno (); + goto done; + } + if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken))) + __seterrno (); + if (hToken != cygheap->user.token) + CloseHandle (hToken); + if (!status) + goto done; + + if (flags & R_OK) + desired |= FILE_READ_DATA; + if (flags & W_OK) + desired |= FILE_WRITE_DATA; + if (flags & X_OK) + desired |= FILE_EXECUTE; + if (!AccessCheck (psd, hIToken, desired, &mapping, + (PPRIVILEGE_SET) pbuf, &plength, &granted, &status)) + __seterrno (); + else if (!status) + set_errno (EACCES); + else + ret = 0; + CloseHandle (hIToken); + done: + debug_printf ("flags %x, ret %d", flags, ret); + return ret; +} diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 9cbea2ff0..a859526d7 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -225,6 +225,7 @@ LONG __stdcall read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd 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); 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); void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, void *sd_buf, DWORD sd_buf_size); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 59bb53146..cd3f2e6e2 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1016,7 +1016,7 @@ fstat64 (int fd, struct __stat64 *buf) path_conv pc (cfd->get_win32_name (), PC_SYM_NOFOLLOW); memset (buf, 0, sizeof (struct __stat64)); res = cfd->fstat (buf, &pc); - if (!res) + if (!res && cfd->get_device () != FH_SOCKET) { if (!buf->st_ino) buf->st_ino = hash_path_name (0, cfd->get_win32_name ()); @@ -1106,7 +1106,7 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow, pc, (DWORD) real_path); memset (buf, 0, sizeof (*buf)); res = fh->fstat (buf, pc); - if (!res) + if (!res && fh->get_device () != FH_SOCKET) { if (!buf->st_ino) buf->st_ino = hash_path_name (0, fh->get_win32_name ()); @@ -1163,8 +1163,6 @@ cygwin_lstat (const char *name, struct __stat32 *buf) return ret; } -extern int acl_access (const char *, int); - extern "C" int access (const char *fn, int flags) { @@ -1176,11 +1174,33 @@ access (const char *fn, int flags) return -1; } - if (allow_ntsec) - return acl_access (fn, flags); + path_conv real_path (fn, PC_SYM_FOLLOW | PC_FULL, stat_suffixes); + if (real_path.error) + { + set_errno (real_path.error); + return -1; + } + + if (!real_path.exists ()) + { + set_errno (ENOENT); + return -1; + } + + if (!(flags & (R_OK | W_OK | X_OK))) + return 0; + + if (real_path.has_attribute (FILE_ATTRIBUTE_READONLY) && (flags & W_OK)) + { + set_errno (EACCES); + return -1; + } + + if (real_path.has_acls () && allow_ntsec) + return check_file_access (real_path, flags); struct __stat64 st; - int r = stat_worker (fn, &st, 0); + int r = stat_worker (real_path, &st, 0); if (r) return -1; r = -1;