* 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:
parent
d9c55a44d6
commit
8304de2e34
|
@ -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.
|
||||
|
|
|
@ -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. */
|
||||
{
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue