Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2003-03-29 15:44:01 +0300
committerCorinna Vinschen <corinna@vinschen.de>2003-03-29 15:44:01 +0300
commit8304de2e34e6977d3314920717ae5de8db8aff02 (patch)
treef911c356574b5a1c063987922cc80a51f16120e5 /winsup/cygwin/syscalls.cc
parentd9c55a44d66ebe3e3e367f2c38f30af0e20b5457 (diff)
* syscalls.cc: Slightly cleanup all utmp functions.
(login): Use mutex to secure against concurrent access to wtmp file. (logout): Rewrite using POSIX calls. (utmp_fd): Initialized to -1 now. Any value < 0 is treated as closed in subsequent functions. (utmp_readonly): New variable, indicating utmp file open for reading only. (internal_setutent): New function implementing setutent(). (setutent): Call internal_setutent now. (endutent): Reset utmp_readonly. (getutent): Return immediately if utmp file can't be opened. (getutid): Ditto. (getutline): Ditto. (pututline): Ditto. Use mutex to secure against concurrent access to utmp file.
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r--winsup/cygwin/syscalls.cc184
1 files changed, 114 insertions, 70 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index b3ae5a0dc..230028017 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -2501,98 +2501,113 @@ login (struct utmp *ut)
pututline (ut);
endutent ();
+ /* Read/write to utmp must be atomic to prevent overriding data
+ by concurrent processes. */
+ HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("wtmp_mutex", 0));
+ if (mutex)
+ while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED)
+ ;
if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0)
{
- (void) write (fd, (char *) ut, sizeof (struct utmp));
- (void) close (fd);
+ write (fd, ut, sizeof *ut);
+ close (fd);
+ }
+ if (mutex)
+ {
+ ReleaseMutex (mutex);
+ CloseHandle (mutex);
}
}
-/* It isn't possible to use unix-style I/O function in logout code because
-cygwin's I/O subsystem may be inaccessible at logout () call time.
-FIXME (cgf): huh?
-*/
extern "C" int
logout (char *line)
{
sigframe thisframe (mainthread);
- int res = 0;
- HANDLE ut_fd;
- static const char path_utmp[] = _PATH_UTMP;
+ struct utmp ut_buf, *ut;
- path_conv win32_path (path_utmp);
- if (win32_path.error)
- return 0;
-
- ut_fd = CreateFile (win32_path.get_win32 (),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_none_nih, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (ut_fd != INVALID_HANDLE_VALUE)
- {
- struct utmp *ut;
- struct utmp ut_buf[100];
- /* FIXME: utmp file access is not 64 bit clean for now. */
- __off32_t pos = 0; /* Position in file */
- DWORD rd;
-
- while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL)
- && rd != 0)
+ memset (&ut_buf, 0, sizeof ut_buf);
+ strncpy (ut_buf.ut_line, line, sizeof ut_buf.ut_line);
+ setutent ();
+ ut = getutline (&ut_buf);
+ if (ut)
+ {
+ int fd;
+
+ /* We can't use ut further since it's a pointer to the static utmp_data
+ area (see below) and would get overwritten in pututline(). So we
+ copy it back to the local ut_buf. */
+ memcpy (&ut_buf, ut, sizeof ut_buf);
+ ut_buf.ut_type = DEAD_PROCESS;
+ memset (ut_buf.ut_user, 0, sizeof ut_buf.ut_user);
+ time (&ut_buf.ut_time);
+ /* Read/write to utmp must be atomic to prevent overriding data
+ by concurrent processes. */
+ HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("wtmp_mutex", 0));
+ if (mutex)
+ while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED)
+ ;
+ if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0)
{
- struct utmp *ut_end = (struct utmp *) ((char *) ut_buf + rd);
-
- for (ut = ut_buf; ut < ut_end; ut++, pos += sizeof (*ut))
- if (ut->ut_name[0]
- && strncmp (ut->ut_line, line, sizeof (ut->ut_line)) == 0)
- /* Found the entry for LINE; mark it as logged out. */
- {
- /* Zero out entries describing who's logged in. */
- memset (ut->ut_name, 0, sizeof (ut->ut_name));
- memset (ut->ut_host, 0, sizeof (ut->ut_host));
- time (&ut->ut_time);
-
- /* Now seek back to the position in utmp at which UT occured,
- and write the new version of UT there. */
- if ((SetFilePointer (ut_fd, pos, 0, FILE_BEGIN) != 0xFFFFFFFF)
- && (WriteFile (ut_fd, (char *) ut, sizeof (*ut),
- &rd, NULL)))
- {
- res = 1;
- break;
- }
- }
+ write (fd, &ut_buf, sizeof ut_buf);
+ close (fd);
}
-
- CloseHandle (ut_fd);
+ if (mutex)
+ {
+ ReleaseMutex (mutex);
+ CloseHandle (mutex);
+ }
+ memset (ut_buf.ut_line, 0, sizeof ut_buf.ut_line);
+ ut_buf.ut_time = 0;
+ pututline (&ut_buf);
+ endutent ();
}
-
- return res;
+ return 1;
}
-static int utmp_fd = -2;
+static int utmp_fd = -1;
+static bool utmp_readonly = false;
static char *utmp_file = (char *) _PATH_UTMP;
static struct utmp utmp_data;
-extern "C" void
-setutent ()
+static void
+internal_setutent (bool force_readwrite)
{
sigframe thisframe (mainthread);
- if (utmp_fd == -2)
- utmp_fd = open (utmp_file, O_RDWR);
+ if (force_readwrite && utmp_readonly)
+ endutent ();
+ if (utmp_fd < 0)
+ {
+ utmp_fd = open (utmp_file, O_RDWR | O_BINARY);
+ /* If open fails, we assume an unprivileged process (who?). In this
+ case we try again for reading only unless the process calls
+ pututline() (==force_readwrite) in which case opening just fails. */
+ if (utmp_fd < 0 && !force_readwrite)
+ {
+ utmp_fd = open (utmp_file, O_RDONLY | O_BINARY);
+ if (utmp_fd >= 0)
+ utmp_readonly = true;
+ }
+ }
else
lseek (utmp_fd, 0, SEEK_SET);
}
extern "C" void
+setutent ()
+{
+ internal_setutent (false);
+}
+
+extern "C" void
endutent ()
{
sigframe thisframe (mainthread);
- if (utmp_fd != -2)
+ if (utmp_fd >= 0)
{
close (utmp_fd);
- utmp_fd = -2;
+ utmp_fd = -1;
+ utmp_readonly = false;
}
}
@@ -2614,9 +2629,13 @@ extern "C" struct utmp *
getutent ()
{
sigframe thisframe (mainthread);
- if (utmp_fd == -2)
- setutent ();
- if (read (utmp_fd, &utmp_data, sizeof (utmp_data)) != sizeof (utmp_data))
+ if (utmp_fd < 0)
+ {
+ internal_setutent (false);
+ if (utmp_fd < 0)
+ return NULL;
+ }
+ if (read (utmp_fd, &utmp_data, sizeof utmp_data) != sizeof utmp_data)
return NULL;
return &utmp_data;
}
@@ -2627,7 +2646,13 @@ getutid (struct utmp *id)
sigframe thisframe (mainthread);
if (check_null_invalid_struct_errno (id))
return NULL;
- while (read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data))
+ if (utmp_fd < 0)
+ {
+ internal_setutent (false);
+ if (utmp_fd < 0)
+ return NULL;
+ }
+ while (read (utmp_fd, &utmp_data, sizeof utmp_data) == sizeof utmp_data)
{
switch (id->ut_type)
{
@@ -2658,12 +2683,18 @@ getutline (struct utmp *line)
sigframe thisframe (mainthread);
if (check_null_invalid_struct_errno (line))
return NULL;
- while (read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data))
+ if (utmp_fd < 0)
+ {
+ internal_setutent (false);
+ if (utmp_fd < 0)
+ return NULL;
+ }
+ while (read (utmp_fd, &utmp_data, sizeof utmp_data) == sizeof utmp_data)
{
if ((utmp_data.ut_type == LOGIN_PROCESS ||
utmp_data.ut_type == USER_PROCESS) &&
!strncmp (utmp_data.ut_line, line->ut_line,
- sizeof (utmp_data.ut_line)))
+ sizeof utmp_data.ut_line))
return &utmp_data;
}
return NULL;
@@ -2675,11 +2706,24 @@ pututline (struct utmp *ut)
sigframe thisframe (mainthread);
if (check_null_invalid_struct (ut))
return;
- setutent ();
+ internal_setutent (true);
+ if (utmp_fd < 0)
+ return;
+ /* Read/write to utmp must be atomic to prevent overriding data
+ by concurrent processes. */
+ HANDLE mutex = CreateMutex (NULL, FALSE, shared_name ("utmp_mutex", 0));
+ if (mutex)
+ while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED)
+ ;
struct utmp *u;
if ((u = getutid (ut)))
- lseek (utmp_fd, -sizeof(struct utmp), SEEK_CUR);
+ lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
else
lseek (utmp_fd, 0, SEEK_END);
- (void) write (utmp_fd, (char *) ut, sizeof (struct utmp));
+ write (utmp_fd, ut, sizeof *ut);
+ if (mutex)
+ {
+ ReleaseMutex (mutex);
+ CloseHandle (mutex);
+ }
}