diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2003-03-29 12:44:01 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2003-03-29 12:44:01 +0000 |
commit | 8304de2e34e6977d3314920717ae5de8db8aff02 (patch) | |
tree | f911c356574b5a1c063987922cc80a51f16120e5 /winsup/cygwin/syscalls.cc | |
parent | d9c55a44d66ebe3e3e367f2c38f30af0e20b5457 (diff) | |
download | cygnal-8304de2e34e6977d3314920717ae5de8db8aff02.tar.gz cygnal-8304de2e34e6977d3314920717ae5de8db8aff02.tar.bz2 cygnal-8304de2e34e6977d3314920717ae5de8db8aff02.zip |
* 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.cc | 184 |
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); + } } |