* 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>
|
2003-03-28 Christopher Faylor <cgf@redhat.com>
|
||||||
|
|
||||||
* Makefile.in: Remove EXE_LDFLAGS. Fix fhandler_CFLAGS typo. Recognize .s suffix.
|
* Makefile.in: Remove EXE_LDFLAGS. Fix fhandler_CFLAGS typo. Recognize .s suffix.
|
||||||
|
@ -2501,98 +2501,113 @@ login (struct utmp *ut)
|
|||||||
|
|
||||||
pututline (ut);
|
pututline (ut);
|
||||||
endutent ();
|
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)
|
if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0)
|
||||||
{
|
{
|
||||||
(void) write (fd, (char *) ut, sizeof (struct utmp));
|
write (fd, ut, sizeof *ut);
|
||||||
(void) close (fd);
|
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
|
extern "C" int
|
||||||
logout (char *line)
|
logout (char *line)
|
||||||
{
|
{
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
int res = 0;
|
struct utmp ut_buf, *ut;
|
||||||
HANDLE ut_fd;
|
|
||||||
static const char path_utmp[] = _PATH_UTMP;
|
|
||||||
|
|
||||||
path_conv win32_path (path_utmp);
|
memset (&ut_buf, 0, sizeof ut_buf);
|
||||||
if (win32_path.error)
|
strncpy (ut_buf.ut_line, line, sizeof ut_buf.ut_line);
|
||||||
return 0;
|
setutent ();
|
||||||
|
ut = getutline (&ut_buf);
|
||||||
ut_fd = CreateFile (win32_path.get_win32 (),
|
if (ut)
|
||||||
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;
|
int fd;
|
||||||
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)
|
/* We can't use ut further since it's a pointer to the static utmp_data
|
||||||
&& rd != 0)
|
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);
|
write (fd, &ut_buf, sizeof ut_buf);
|
||||||
|
close (fd);
|
||||||
for (ut = ut_buf; ut < ut_end; ut++, pos += sizeof (*ut))
|
}
|
||||||
if (ut->ut_name[0]
|
if (mutex)
|
||||||
&& 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. */
|
ReleaseMutex (mutex);
|
||||||
memset (ut->ut_name, 0, sizeof (ut->ut_name));
|
CloseHandle (mutex);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
memset (ut_buf.ut_line, 0, sizeof ut_buf.ut_line);
|
||||||
|
ut_buf.ut_time = 0;
|
||||||
|
pututline (&ut_buf);
|
||||||
|
endutent ();
|
||||||
}
|
}
|
||||||
}
|
return 1;
|
||||||
|
|
||||||
CloseHandle (ut_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int utmp_fd = -2;
|
static int utmp_fd = -1;
|
||||||
|
static bool utmp_readonly = false;
|
||||||
static char *utmp_file = (char *) _PATH_UTMP;
|
static char *utmp_file = (char *) _PATH_UTMP;
|
||||||
|
|
||||||
static struct utmp utmp_data;
|
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
|
extern "C" void
|
||||||
setutent ()
|
setutent ()
|
||||||
{
|
{
|
||||||
sigframe thisframe (mainthread);
|
internal_setutent (false);
|
||||||
if (utmp_fd == -2)
|
|
||||||
utmp_fd = open (utmp_file, O_RDWR);
|
|
||||||
else
|
|
||||||
lseek (utmp_fd, 0, SEEK_SET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
endutent ()
|
endutent ()
|
||||||
{
|
{
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
if (utmp_fd != -2)
|
if (utmp_fd >= 0)
|
||||||
{
|
{
|
||||||
close (utmp_fd);
|
close (utmp_fd);
|
||||||
utmp_fd = -2;
|
utmp_fd = -1;
|
||||||
|
utmp_readonly = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2614,9 +2629,13 @@ extern "C" struct utmp *
|
|||||||
getutent ()
|
getutent ()
|
||||||
{
|
{
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
if (utmp_fd == -2)
|
if (utmp_fd < 0)
|
||||||
setutent ();
|
{
|
||||||
if (read (utmp_fd, &utmp_data, sizeof (utmp_data)) != sizeof (utmp_data))
|
internal_setutent (false);
|
||||||
|
if (utmp_fd < 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (read (utmp_fd, &utmp_data, sizeof utmp_data) != sizeof utmp_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
return &utmp_data;
|
return &utmp_data;
|
||||||
}
|
}
|
||||||
@ -2627,7 +2646,13 @@ getutid (struct utmp *id)
|
|||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
if (check_null_invalid_struct_errno (id))
|
if (check_null_invalid_struct_errno (id))
|
||||||
return NULL;
|
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)
|
switch (id->ut_type)
|
||||||
{
|
{
|
||||||
@ -2658,12 +2683,18 @@ getutline (struct utmp *line)
|
|||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
if (check_null_invalid_struct_errno (line))
|
if (check_null_invalid_struct_errno (line))
|
||||||
return NULL;
|
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 ||
|
if ((utmp_data.ut_type == LOGIN_PROCESS ||
|
||||||
utmp_data.ut_type == USER_PROCESS) &&
|
utmp_data.ut_type == USER_PROCESS) &&
|
||||||
!strncmp (utmp_data.ut_line, line->ut_line,
|
!strncmp (utmp_data.ut_line, line->ut_line,
|
||||||
sizeof (utmp_data.ut_line)))
|
sizeof utmp_data.ut_line))
|
||||||
return &utmp_data;
|
return &utmp_data;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2675,11 +2706,24 @@ pututline (struct utmp *ut)
|
|||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
if (check_null_invalid_struct (ut))
|
if (check_null_invalid_struct (ut))
|
||||||
return;
|
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;
|
struct utmp *u;
|
||||||
if ((u = getutid (ut)))
|
if ((u = getutid (ut)))
|
||||||
lseek (utmp_fd, -sizeof(struct utmp), SEEK_CUR);
|
lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
|
||||||
else
|
else
|
||||||
lseek (utmp_fd, 0, SEEK_END);
|
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…
x
Reference in New Issue
Block a user