* 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.
This commit is contained in:
Corinna Vinschen 2003-03-29 12:44:01 +00:00
parent d9c55a44d6
commit 8304de2e34
2 changed files with 131 additions and 69 deletions

View File

@ -1,3 +1,21 @@
2003-03-29 Corinna Vinschen <corinna@vinschen.de>
* 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.
2003-03-28 Christopher Faylor <cgf@redhat.com>
* Makefile.in: Remove EXE_LDFLAGS. Fix fhandler_CFLAGS typo. Recognize .s suffix.

View File

@ -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)
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)
{
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;
int fd;
while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL)
&& rd != 0)
/* 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. */
write (fd, &ut_buf, sizeof ut_buf);
close (fd);
}
if (mutex)
{
/* 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;
ReleaseMutex (mutex);
CloseHandle (mutex);
}
memset (ut_buf.ut_line, 0, sizeof ut_buf.ut_line);
ut_buf.ut_time = 0;
pututline (&ut_buf);
endutent ();
}
}
CloseHandle (ut_fd);
}
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;
static void
internal_setutent (bool force_readwrite)
{
sigframe thisframe (mainthread);
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 ()
{
sigframe thisframe (mainthread);
if (utmp_fd == -2)
utmp_fd = open (utmp_file, O_RDWR);
else
lseek (utmp_fd, 0, SEEK_SET);
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);
}
}