mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-09 19:00:08 +00:00
Update.
2000-04-18 Ulrich Drepper <drepper@redhat.com> * login/programs/connection.c: Removed. * login/programs/database.c Removed. * login/programs/error.c: Removed. * login/programs/request.c: Removed. * login/programs/xtmp.c: Removed. * login/programs/xtmp.h: Removed. * login/Makefile: Remove rules for utmpd. * login/README.utmpd: Removed.
This commit is contained in:
parent
d9317f3d92
commit
74f998221d
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
|||||||
|
2000-04-18 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
|
* login/programs/connection.c: Removed.
|
||||||
|
* login/programs/database.c Removed.
|
||||||
|
* login/programs/error.c: Removed.
|
||||||
|
* login/programs/request.c: Removed.
|
||||||
|
* login/programs/xtmp.c: Removed.
|
||||||
|
* login/programs/xtmp.h: Removed.
|
||||||
|
* login/Makefile: Remove rules for utmpd.
|
||||||
|
* login/README.utmpd: Removed.
|
||||||
|
|
||||||
2000-04-18 Andreas Jaeger <aj@suse.de>
|
2000-04-18 Andreas Jaeger <aj@suse.de>
|
||||||
|
|
||||||
* sysdeps/mips/dl-machine.h (elf_machine_rel): Fix relocation.
|
* sysdeps/mips/dl-machine.h (elf_machine_rel): Fix relocation.
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
With the introduction of version 2 of the GNU C Library the format of
|
|
||||||
the UTMP and WTMP files changed for some configurations (see Q&A `Why
|
|
||||||
does getlogin() always return NULL on my Linux box?' of the FAQ).
|
|
||||||
This version of the GNU C Library contains a solution for the problems
|
|
||||||
this may cause, by providing an UTMP daemon `utmpd'.
|
|
||||||
|
|
||||||
Do I need it?
|
|
||||||
=============
|
|
||||||
|
|
||||||
If your configuration is one of the following:
|
|
||||||
|
|
||||||
i[3456]86-*-linux-gnu Linux-2.0 on Intel
|
|
||||||
m68k-*-linux-gnu Linux-2.0 on Motorola 680x0
|
|
||||||
|
|
||||||
you might need it, so please read on. If it is not, please read the
|
|
||||||
section titled `Programming' at the end of this text.
|
|
||||||
|
|
||||||
In principle, you only need the daemon if you want to keep using old
|
|
||||||
programs linked against the previous version of the Linux C Library
|
|
||||||
(libc5). In addition you will need the daemon if you are running
|
|
||||||
Linux on Intel, and you are planning to use iBCS (Intel Binary
|
|
||||||
Compatibility Standard). If you have no libc5 programs left on your
|
|
||||||
system and you are not using iBCS, it is probably better not to
|
|
||||||
install the daemon since it uses (a small amount of) memory and CPU
|
|
||||||
time. But apart from that it shouldn't hurt to install `utmpd', so
|
|
||||||
when in doubt install it anyway.
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
The installation process (`make install') already places the `utmpd'
|
|
||||||
binary in $(sbindir). The only thing you have to do is modifying your
|
|
||||||
startup scripts to start the daemon. Unfortunately this is a bit of a
|
|
||||||
hassle, since the layout of these scripts is not standardized. You
|
|
||||||
should try to find the command that creates the file `/var/run/utmp'.
|
|
||||||
This is usually done in a script named `/etc/rc', `/etc/init.d/boot'
|
|
||||||
(Debian) or `/etc/rc.d/rc.S' (Slackware). You could try:
|
|
||||||
|
|
||||||
grep utmp /etc/* /etc/init.d/* /etc/rc.d/*
|
|
||||||
|
|
||||||
to find the right script. The creation of `/var/run/utmp' is usually
|
|
||||||
done with a command like:
|
|
||||||
|
|
||||||
: > /var/run/utmp
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
cat /dev/null > /var/run/utmp
|
|
||||||
|
|
||||||
Now add a line before this command to create the file `/var/run/utmpx'
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
: > /var/run/utmpx
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
cat /dev/null > /var/run/utmpx
|
|
||||||
|
|
||||||
whatever you prefer, and after this command, add a line to start the
|
|
||||||
daemon
|
|
||||||
|
|
||||||
utmpd
|
|
||||||
|
|
||||||
The entire fragment could look something like
|
|
||||||
|
|
||||||
# Clean up /var/run and create /var/run/utmp so that we can login.
|
|
||||||
( cd /var/run && find . ! -type d -exec rm -f -- {} \; )
|
|
||||||
: > /var/run/utmpx
|
|
||||||
: > /var/run/utmp
|
|
||||||
utmpd
|
|
||||||
|
|
||||||
If the file `/var/log/wtmp' exists on your system, you will probably
|
|
||||||
want to create the file `/var/log/wtmpx'. Programs linked against the
|
|
||||||
GNU C Library will now write to `/var/log/wtmpx', while programs
|
|
||||||
linked against the old library will continue to write to
|
|
||||||
`/var/log/wtmp'. Of course this means that the information gets
|
|
||||||
spread over two files. We hope to provide a better solution in the
|
|
||||||
future.
|
|
||||||
|
|
||||||
After a reboot, user accounting should be working again. If not,
|
|
||||||
please refer to the section titled `Troubleshooting' below before
|
|
||||||
submitting a bug report.
|
|
||||||
|
|
||||||
|
|
||||||
What is `utmpd' doing?
|
|
||||||
======================
|
|
||||||
|
|
||||||
After installation there will be two files that store the user
|
|
||||||
accounting information: `/var/run/utmp' and `/var/run/utmpx'. The
|
|
||||||
file `/var/run/utmp' will be in the old format so libc5 programs will
|
|
||||||
continue to work (even if they are broken and do not use the library
|
|
||||||
functions to access the user accounting database). And on Intel, you
|
|
||||||
can safely link `/var/run/utmp' to `/etc/utmp' for iBCS programs.
|
|
||||||
Programs linked against the new GNU C Library (glibc2) will contact
|
|
||||||
the daemon for all user accounting database access. The daemon will
|
|
||||||
store its information in `/var/run/utmpx' and keeps this file in sync
|
|
||||||
with `/var/run/utmp'. Entries added to `/var/run/utmpx' will be
|
|
||||||
converted to the old format and will be added to `/var/run/utmp' and
|
|
||||||
vice versa. This way both libc5 and glibc2 see the same information
|
|
||||||
in the same fields of `struct utmp'. Of course libc5 programs see only
|
|
||||||
part of the information that glibc2 programs see because not all
|
|
||||||
members of the glibc2 `struct utmp' are present in the libc5 `struct
|
|
||||||
utmp'. For the same reason libc5 will see a truncated version of
|
|
||||||
those fields where the length of the glibc2 field is larger than the
|
|
||||||
corresponding libc5 field (ut_user, ut_line, ut_host).
|
|
||||||
|
|
||||||
|
|
||||||
Troubleshooting
|
|
||||||
===============
|
|
||||||
|
|
||||||
If user accounting is not working on your system, e.g. programs like
|
|
||||||
`who' or `logname' return rubbish, or you cannot login, make
|
|
||||||
sure that:
|
|
||||||
|
|
||||||
* The file `/var/run/utmpx' exists.
|
|
||||||
|
|
||||||
* The file `/var/log/wtmpx' exists.
|
|
||||||
|
|
||||||
* No program linked against the GNU C Library (libc6) is accessing
|
|
||||||
`/var/run/utmp' directly (see the section on `Programming' below).
|
|
||||||
|
|
||||||
If that does not solve your problems, please use the `glibcbug' script
|
|
||||||
to report the problem to <bugs@gnu.org>.
|
|
||||||
|
|
||||||
The `utmpd' daemon uses `syslogd' to report problems. It uses the
|
|
||||||
`daemon' facility and `warning' and `error' levels. Alternatively you
|
|
||||||
could use the following option to ease debugging:
|
|
||||||
|
|
||||||
`--debug'
|
|
||||||
Use this option if you want the daemon to output its warnings and
|
|
||||||
error messages to the terminal instead of sending them to the
|
|
||||||
system logger (`syslogd'). When using this option the daemon does
|
|
||||||
not auto-background itself.
|
|
||||||
|
|
||||||
To use this option you should first kill the daemon that is already
|
|
||||||
running, and start a fresh one with the desired option:
|
|
||||||
|
|
||||||
kill `cat /var/run/utmpd.pid`
|
|
||||||
utmpd --debug
|
|
||||||
|
|
||||||
Please include any warnings or error messages from `utmpd' in your
|
|
||||||
bug reports.
|
|
||||||
|
|
||||||
|
|
||||||
Programming
|
|
||||||
===========
|
|
||||||
|
|
||||||
In order for the `utmpd' approach to work it is essential that NO
|
|
||||||
program EVER accesses the UTMP and WTMP files directly. Instead, a
|
|
||||||
program should use ONLY the available library functions:
|
|
||||||
|
|
||||||
* utmpname() Select the database used (UTMP, WTMP, ...).
|
|
||||||
* setutent() Open the database.
|
|
||||||
* getutent() Read the next entry from the database.
|
|
||||||
* getutid() Search for the next entry with a specific ID.
|
|
||||||
* getutline() Search for the next entry for a specific line.
|
|
||||||
* pututline() Write an entry to the database.
|
|
||||||
* endutent() Close the database.
|
|
||||||
* updwtmp() Add an entry to a database (WTMP, ...).
|
|
||||||
|
|
||||||
For details, please refer to `The GNU C Library Reference Manual',
|
|
||||||
which also contains information about some additional functions
|
|
||||||
derived from BSD and XPG that may be of interest. The command
|
|
||||||
|
|
||||||
info libc "User Accounting Database"
|
|
||||||
|
|
||||||
should point you at the right location.
|
|
||||||
|
|
||||||
If you encounter a program that reads from or, even worse, writes to
|
|
||||||
the UTMP and WTMP files directly, please report this as a bug to the
|
|
||||||
author of that program. Note that the files referred to by the macros
|
|
||||||
`_PATH_UTMP' and `_PATH_WTMP' might even disappear in the future, so
|
|
||||||
please do not use these, except in a call to `utmpname()' or
|
|
||||||
`updwtmp()', not even to check their existence.
|
|
@ -1,180 +0,0 @@
|
|||||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "utmpd-private.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes for the local functions. */
|
|
||||||
static client_connection *alloc_connection (void);
|
|
||||||
static void free_connection (client_connection *connection);
|
|
||||||
static int set_nonblock_flag (int desc, int value);
|
|
||||||
|
|
||||||
|
|
||||||
/* The head of the connection list. */
|
|
||||||
static client_connection *connection_list = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
/* Accept connection on SOCK, with access permissions given by ACCESS.
|
|
||||||
Returns a pointer to a newly allocated client_connection if
|
|
||||||
successful, NULL if not. */
|
|
||||||
client_connection *
|
|
||||||
accept_connection (int sock, int access)
|
|
||||||
{
|
|
||||||
client_connection *connection;
|
|
||||||
|
|
||||||
connection = alloc_connection ();
|
|
||||||
if (connection == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
connection->sock = accept (sock, NULL, NULL);
|
|
||||||
connection->access = access;
|
|
||||||
if (connection->sock < 0)
|
|
||||||
{
|
|
||||||
free_connection (connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set_nonblock_flag (connection->sock, 1) < 0)
|
|
||||||
{
|
|
||||||
close_connection (connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Close CONNECTION. */
|
|
||||||
void
|
|
||||||
close_connection (client_connection *connection)
|
|
||||||
{
|
|
||||||
close (connection->sock);
|
|
||||||
free_connection (connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the connection for SOCK. */
|
|
||||||
client_connection *
|
|
||||||
find_connection (int sock)
|
|
||||||
{
|
|
||||||
client_connection *connection;
|
|
||||||
|
|
||||||
for (connection = connection_list; connection;
|
|
||||||
connection = connection->next)
|
|
||||||
{
|
|
||||||
if (connection->sock == sock)
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static client_connection *
|
|
||||||
alloc_connection (void)
|
|
||||||
{
|
|
||||||
client_connection *connection;
|
|
||||||
size_t read_bufsize = 1024;
|
|
||||||
size_t write_bufsize = 1024;
|
|
||||||
|
|
||||||
connection = (client_connection *)malloc (sizeof (client_connection));
|
|
||||||
if (connection == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset (connection, 0, sizeof (client_connection));
|
|
||||||
|
|
||||||
/* Allocate read buffer. */
|
|
||||||
connection->read_base = malloc (read_bufsize);
|
|
||||||
connection->read_ptr = connection->read_base;
|
|
||||||
connection->read_end = connection->read_base + read_bufsize;
|
|
||||||
if (connection->read_base == NULL)
|
|
||||||
{
|
|
||||||
free (connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate write buffer. */
|
|
||||||
connection->write_base = malloc (write_bufsize);
|
|
||||||
connection->write_ptr = connection->write_base;
|
|
||||||
connection->write_end = connection->write_base + write_bufsize;
|
|
||||||
if (connection->write_base == NULL)
|
|
||||||
{
|
|
||||||
free (connection->read_base);
|
|
||||||
free (connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link connection. */
|
|
||||||
connection->next = connection_list;
|
|
||||||
connection_list = connection;
|
|
||||||
if (connection->next)
|
|
||||||
connection->next->prev = connection;
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_connection (client_connection *connection)
|
|
||||||
{
|
|
||||||
/* Unlink connection. */
|
|
||||||
if (connection->next)
|
|
||||||
connection->next->prev = connection->prev;
|
|
||||||
if (connection->prev)
|
|
||||||
connection->prev->next = connection->next;
|
|
||||||
|
|
||||||
/* Take care of the head of the list. */
|
|
||||||
if (connection == connection_list)
|
|
||||||
connection_list = connection->next;
|
|
||||||
|
|
||||||
/* Free buffers. */
|
|
||||||
if (connection->read_base)
|
|
||||||
free (connection->read_base);
|
|
||||||
if (connection->write_base)
|
|
||||||
free (connection->write_base);
|
|
||||||
|
|
||||||
free (connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
|
|
||||||
or clear the flag if VALUE is 0.
|
|
||||||
Return 0 on success, or -1 on error with `errno' set. */
|
|
||||||
static int
|
|
||||||
set_nonblock_flag (int desc, int value)
|
|
||||||
{
|
|
||||||
int oldflags = fcntl (desc, F_GETFL, 0);
|
|
||||||
/* If reading the flags failed, return error indication now. */
|
|
||||||
if (oldflags == -1)
|
|
||||||
return -1;
|
|
||||||
/* Set just the flag we want to set. */
|
|
||||||
if (value != 0)
|
|
||||||
oldflags |= O_NONBLOCK;
|
|
||||||
else
|
|
||||||
oldflags &= ~O_NONBLOCK;
|
|
||||||
/* Store modified flag word in the descriptor. */
|
|
||||||
return fcntl (desc, F_SETFL, oldflags);
|
|
||||||
}
|
|
@ -1,543 +0,0 @@
|
|||||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utmp.h>
|
|
||||||
#include <libintl.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "utmpd-private.h"
|
|
||||||
#include "xtmp.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes for the local functions. */
|
|
||||||
static int initialize_database (utmp_database *database);
|
|
||||||
static int store_state_entry (utmp_database *database, int old_position,
|
|
||||||
const struct utmp *old_entry);
|
|
||||||
static int store_process_entry (utmp_database *database, int old_position,
|
|
||||||
const struct utmp *old_entry);
|
|
||||||
static int replace_entry (utmp_database *database, int old_position,
|
|
||||||
int new_position, const struct utmp *entry);
|
|
||||||
static int store_entry (utmp_database *database, int position,
|
|
||||||
const struct utmp *entry);
|
|
||||||
static int get_mtime (int filedes, time_t *timer);
|
|
||||||
|
|
||||||
|
|
||||||
/* Open the database specified by FILE and merge it with the contents
|
|
||||||
of the old format file specified by OLD_FILE. Returns a pointer to
|
|
||||||
a newly allocated structure describing the database, or NULL on
|
|
||||||
error. */
|
|
||||||
utmp_database *
|
|
||||||
open_database (const char *file, const char *old_file)
|
|
||||||
{
|
|
||||||
mode_t mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
|
|
||||||
utmp_database *database;
|
|
||||||
|
|
||||||
/* Allocate memory. */
|
|
||||||
database = (utmp_database *) malloc (sizeof (utmp_database));
|
|
||||||
if (database == NULL)
|
|
||||||
{
|
|
||||||
error (0, 0, _("memory exhausted"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset (database, 0, sizeof (utmp_database));
|
|
||||||
|
|
||||||
/* Open database, create it if it doesn't exist already. */
|
|
||||||
database->fd = open (file, O_RDWR | O_CREAT, mode);
|
|
||||||
if (database->fd < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", file);
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
database->file = strdup (file);
|
|
||||||
if (database->file == NULL)
|
|
||||||
{
|
|
||||||
error (0, 0, _("memory exhausted"));
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_file)
|
|
||||||
{
|
|
||||||
database->old_fd = open (old_file, O_RDWR|O_CREAT, mode);
|
|
||||||
if (database->old_fd < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", old_file);
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
database->old_file = strdup (old_file);
|
|
||||||
if (database->old_file == NULL)
|
|
||||||
{
|
|
||||||
error (0, 0, _("memory exhausted"));
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize database. */
|
|
||||||
if (initialize_database (database) < 0)
|
|
||||||
goto return_error;
|
|
||||||
|
|
||||||
return database;
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
close_database (database);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Synchronize DATABASE. */
|
|
||||||
int
|
|
||||||
synchronize_database (utmp_database *database)
|
|
||||||
{
|
|
||||||
assert (database);
|
|
||||||
|
|
||||||
/* Check if there is a file in the old format, that we have to
|
|
||||||
synchronize with. */
|
|
||||||
if (database->old_file)
|
|
||||||
{
|
|
||||||
time_t curtime;
|
|
||||||
time_t mtime;
|
|
||||||
|
|
||||||
curtime = time (NULL);
|
|
||||||
|
|
||||||
if (get_mtime (database->old_fd, &mtime) < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, _("%s: cannot get modification time"),
|
|
||||||
database->old_file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mtime >= database->mtime)
|
|
||||||
{
|
|
||||||
int position = 0;
|
|
||||||
struct utmp entry;
|
|
||||||
struct utmp old_entry;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (read_old_entry (database, position, &old_entry) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (read_entry (database, position, &entry) < 0
|
|
||||||
|| !compare_entry (&old_entry, &entry))
|
|
||||||
{
|
|
||||||
if (write_entry (database, position, &old_entry) < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", database->file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
database->mtime = curtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Close DATABASE. */
|
|
||||||
void
|
|
||||||
close_database (utmp_database *database)
|
|
||||||
{
|
|
||||||
assert (database);
|
|
||||||
|
|
||||||
if (database->fd >= 0)
|
|
||||||
close (database->fd);
|
|
||||||
|
|
||||||
if (database->old_fd >= 0)
|
|
||||||
close (database->old_fd);
|
|
||||||
|
|
||||||
/* Free allocated memory. */
|
|
||||||
if (database->file)
|
|
||||||
free (database->file);
|
|
||||||
if (database->old_file)
|
|
||||||
free (database->old_file);
|
|
||||||
free (database);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Read the entry at POSITION in DATABASE and store the result in
|
|
||||||
ENTRY. Returns 0 if successful, -1 if not. */
|
|
||||||
int
|
|
||||||
read_entry (utmp_database *database, int position, struct utmp *entry)
|
|
||||||
{
|
|
||||||
ssize_t nbytes;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
offset = position * sizeof (struct utmp);
|
|
||||||
if (lseek (database->fd, offset, SEEK_SET) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
nbytes = read (database->fd, entry, sizeof (struct utmp));
|
|
||||||
if (nbytes != sizeof (struct utmp))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Write ENTRY at POSITION in DATABASE. Returns 0 if successful, -1
|
|
||||||
on error. */
|
|
||||||
int
|
|
||||||
write_entry (utmp_database *database, int position,
|
|
||||||
const struct utmp *entry)
|
|
||||||
{
|
|
||||||
int result = -1;
|
|
||||||
struct flock fl;
|
|
||||||
ssize_t nbytes;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
/* Try to lock the file. */
|
|
||||||
memset (&fl, 0, sizeof (struct flock));
|
|
||||||
fl.l_type = F_WRLCK;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fcntl (database->fd, F_SETLKW, &fl);
|
|
||||||
|
|
||||||
offset = position * sizeof (struct utmp);
|
|
||||||
if (lseek (database->fd, offset, SEEK_SET) < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
nbytes = write (database->fd, entry, sizeof (struct utmp));
|
|
||||||
if (nbytes != sizeof (struct utmp))
|
|
||||||
{
|
|
||||||
ftruncate (database->fd, offset);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
/* And unlock the file. */
|
|
||||||
fl.l_type = F_UNLCK;
|
|
||||||
fcntl (database->fd, F_SETLKW, &fl);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Append ENTRY to DATABASE. Returns the position of the appended
|
|
||||||
entry if successful, or -1 on error. */
|
|
||||||
int
|
|
||||||
append_entry (utmp_database *database, const struct utmp *entry)
|
|
||||||
{
|
|
||||||
int result = -1;
|
|
||||||
struct flock fl;
|
|
||||||
ssize_t nbytes;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
/* Try to lock the file. */
|
|
||||||
memset (&fl, 0, sizeof (struct flock));
|
|
||||||
fl.l_type = F_WRLCK;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fcntl (database->fd, F_SETLKW, &fl);
|
|
||||||
|
|
||||||
offset = lseek (database->fd, 0, SEEK_END);
|
|
||||||
if (offset % sizeof (struct utmp) != 0)
|
|
||||||
{
|
|
||||||
offset -= offset % sizeof (struct utmp);
|
|
||||||
ftruncate (database->fd, offset);
|
|
||||||
|
|
||||||
if (lseek (database->fd, 0, SEEK_END) < 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = write (database->fd, entry, sizeof (struct utmp));
|
|
||||||
if (nbytes != sizeof (struct utmp))
|
|
||||||
{
|
|
||||||
ftruncate (database->fd, offset);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = offset / sizeof (struct utmp);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
/* And unlock the file. */
|
|
||||||
fl.l_type = F_UNLCK;
|
|
||||||
fcntl (database->fd, F_SETLKW, &fl);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
read_old_entry (utmp_database *database, int position,
|
|
||||||
struct utmp *entry)
|
|
||||||
{
|
|
||||||
struct xtmp old_entry;
|
|
||||||
ssize_t nbytes;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
offset = position * sizeof (struct xtmp);
|
|
||||||
if (lseek (database->old_fd, offset, SEEK_SET) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
nbytes = read (database->old_fd, &old_entry, sizeof (struct xtmp));
|
|
||||||
if (nbytes != sizeof (struct xtmp))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
xtmp_to_utmp (&old_entry, entry);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
write_old_entry (utmp_database *database, int position,
|
|
||||||
const struct utmp *entry)
|
|
||||||
{
|
|
||||||
struct xtmp old_entry;
|
|
||||||
ssize_t nbytes;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
utmp_to_xtmp (entry, &old_entry);
|
|
||||||
|
|
||||||
offset = position * sizeof (struct xtmp);
|
|
||||||
if (lseek (database->old_fd, offset, SEEK_SET) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
nbytes = write (database->old_fd, &old_entry, sizeof (struct xtmp));
|
|
||||||
if (nbytes != sizeof (struct xtmp))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize DATABASE. */
|
|
||||||
static int
|
|
||||||
initialize_database (utmp_database *database)
|
|
||||||
{
|
|
||||||
struct utmp entry;
|
|
||||||
int position = 0;
|
|
||||||
|
|
||||||
assert (database);
|
|
||||||
|
|
||||||
/* Check if there is a file in the old format to read. */
|
|
||||||
if (database->old_file)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (read_old_entry (database, position, &entry) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
/* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
|
|
||||||
NEW_TIME, search for an entry of the same type in the
|
|
||||||
database, and replace it if the entry in the file is newer. */
|
|
||||||
if (entry.ut_type == RUN_LVL || entry.ut_type == BOOT_TIME
|
|
||||||
|| entry.ut_type == OLD_TIME || entry.ut_type == NEW_TIME)
|
|
||||||
{
|
|
||||||
if (store_state_entry (database, position, &entry) < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", database->file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (store_process_entry (database, position, &entry) < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", database->file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update position. */
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (read_entry (database, position, &entry) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (write_old_entry (database, position, &entry) < 0)
|
|
||||||
{
|
|
||||||
error (0, errno, "%s", database->file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update position. */
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return synchronize_database (database);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
static int
|
|
||||||
store_state_entry (utmp_database *database, int old_position,
|
|
||||||
const struct utmp *old_entry)
|
|
||||||
{
|
|
||||||
struct utmp new_entry;
|
|
||||||
int new_position = 0;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
assert (old_entry->ut_type == RUN_LVL
|
|
||||||
|| old_entry->ut_type == BOOT_TIME
|
|
||||||
|| old_entry->ut_type == OLD_TIME
|
|
||||||
|| old_entry->ut_type == NEW_TIME);
|
|
||||||
|
|
||||||
while (!found)
|
|
||||||
{
|
|
||||||
/* Read the next entry. */
|
|
||||||
if (read_entry (database, new_position, &new_entry) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (old_entry->ut_type == new_entry.ut_type)
|
|
||||||
{
|
|
||||||
found = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update position. */
|
|
||||||
new_position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
const struct utmp *entry;
|
|
||||||
|
|
||||||
if (
|
|
||||||
#if _HAVE_UT_TV - 0
|
|
||||||
old_entry->ut_tv.tv_sec > new_entry.ut_tv.tv_sec
|
|
||||||
#else
|
|
||||||
old_entry->ut_time > new_entry.ut_time
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
entry = old_entry;
|
|
||||||
else
|
|
||||||
entry = &new_entry;
|
|
||||||
|
|
||||||
return replace_entry (database, old_position, new_position, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return store_entry (database, old_position, old_entry);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
store_process_entry (utmp_database *database, int old_position,
|
|
||||||
const struct utmp *old_entry)
|
|
||||||
{
|
|
||||||
struct utmp new_entry;
|
|
||||||
int new_position = 0;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
while (!found)
|
|
||||||
{
|
|
||||||
/* Read the next entry. */
|
|
||||||
if (read_entry (database, new_position, &new_entry) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (proc_utmp_eq (old_entry, &new_entry))
|
|
||||||
{
|
|
||||||
found = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update position. */
|
|
||||||
new_position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
const struct utmp *entry;
|
|
||||||
|
|
||||||
if (
|
|
||||||
#if _HAVE_UT_TV - 0
|
|
||||||
old_entry->ut_tv.tv_sec > new_entry.ut_tv.tv_sec
|
|
||||||
#else
|
|
||||||
old_entry->ut_time > new_entry.ut_time
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
entry = old_entry;
|
|
||||||
else
|
|
||||||
entry = &new_entry;
|
|
||||||
|
|
||||||
return replace_entry (database, old_position, new_position, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return store_entry (database, old_position, old_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
replace_entry (utmp_database *database, int old_position, int new_position,
|
|
||||||
const struct utmp *entry)
|
|
||||||
{
|
|
||||||
struct utmp tmp;
|
|
||||||
|
|
||||||
if (read_entry (database, old_position, &tmp) < 0
|
|
||||||
|| write_entry (database, old_position, entry) < 0
|
|
||||||
|| write_entry (database, new_position, &tmp) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
store_entry (utmp_database *database, int position,
|
|
||||||
const struct utmp *entry)
|
|
||||||
{
|
|
||||||
struct utmp tmp;
|
|
||||||
|
|
||||||
if (read_entry (database, position, &tmp) < 0)
|
|
||||||
return write_entry (database, position, entry);
|
|
||||||
|
|
||||||
if (write_entry (database, position, entry) < 0
|
|
||||||
|| append_entry (database, &tmp) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Get modification time of the file with file descriptor FILEDES and
|
|
||||||
put it in TIMER. Returns 0 if successful, -1 if not. */
|
|
||||||
static int
|
|
||||||
get_mtime (int filedes, time_t *timer)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (fstat (filedes, &st) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*timer = st.st_mtime;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
#include "utmpd-private.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* This variable indicates if we have forked. If set, we log messages
|
|
||||||
via the system logger. Otherwise we simply print the program name
|
|
||||||
and the message to standard error. */
|
|
||||||
int forked = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* Log error message MESSAGE, which is a printf-style format string
|
|
||||||
with optional args.
|
|
||||||
If ERRNUM is nonzero, also log its corresponding system error message.
|
|
||||||
Exit with status STATUS if it is nonzero. */
|
|
||||||
void
|
|
||||||
error (int status, int errnum, const char *message, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
char *buffer = NULL;
|
|
||||||
|
|
||||||
va_start (ap, message);
|
|
||||||
vasprintf (&buffer, message, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
if (forked)
|
|
||||||
{
|
|
||||||
if (errnum == 0)
|
|
||||||
syslog (LOG_ERR, "%s", buffer);
|
|
||||||
else
|
|
||||||
syslog (LOG_ERR, "%s: %s", buffer, strerror (errnum));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (errnum == 0)
|
|
||||||
fprintf (stderr, "%s: %s\n", program_invocation_name, buffer);
|
|
||||||
else
|
|
||||||
fprintf (stderr, "%s: %s: %s\n", program_invocation_name, buffer,
|
|
||||||
strerror (errnum));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer)
|
|
||||||
free (buffer);
|
|
||||||
|
|
||||||
if (status)
|
|
||||||
exit (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Log warning message MESSAGE, which is a printf-style format string
|
|
||||||
with optional args.
|
|
||||||
If ERRNUM is nonzero, also log its corresponding system error message. */
|
|
||||||
void
|
|
||||||
warning (int errnum, const char *message, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
char *buffer = NULL;
|
|
||||||
|
|
||||||
va_start (ap, message);
|
|
||||||
vasprintf (&buffer, message, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
if (forked)
|
|
||||||
{
|
|
||||||
if (errnum == 0)
|
|
||||||
syslog (LOG_WARNING, "%s", buffer);
|
|
||||||
else
|
|
||||||
syslog (LOG_WARNING, "%s: %s", buffer, strerror (errnum));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (errnum == 0)
|
|
||||||
printf ("%s: %s\n", program_invocation_name, buffer);
|
|
||||||
else
|
|
||||||
printf ("%s: %s: %s\n", program_invocation_name, buffer,
|
|
||||||
strerror (errnum));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer)
|
|
||||||
free (buffer);
|
|
||||||
}
|
|
@ -1,646 +0,0 @@
|
|||||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utmp.h>
|
|
||||||
#include <libintl.h>
|
|
||||||
|
|
||||||
#include "utmpd.h"
|
|
||||||
#include "utmpd-private.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes for the local functions. */
|
|
||||||
static int process_request (client_connection *connection);
|
|
||||||
static int send_reply (client_connection *connect, const reply_header *reply);
|
|
||||||
|
|
||||||
static int do_setutent (client_connection *connection);
|
|
||||||
static int do_getutent (client_connection *connection);
|
|
||||||
static int do_endutent (client_connection *connection);
|
|
||||||
static int do_getutline (client_connection *connection);
|
|
||||||
static int do_getutid (client_connection *connection);
|
|
||||||
static int do_pututline (client_connection *connection);
|
|
||||||
static int do_updwtmp (client_connection *connection);
|
|
||||||
|
|
||||||
static int internal_getut_r (client_connection *connection,
|
|
||||||
const struct utmp *id, struct utmp *buffer);
|
|
||||||
|
|
||||||
|
|
||||||
/* Read data from the client on CONNECTION. */
|
|
||||||
int
|
|
||||||
read_data (client_connection *connection)
|
|
||||||
{
|
|
||||||
ssize_t nbytes;
|
|
||||||
|
|
||||||
assert (connection);
|
|
||||||
assert ((connection->read_end - connection->read_ptr) > 0);
|
|
||||||
|
|
||||||
/* Read data. */
|
|
||||||
nbytes = read (connection->sock, connection->read_ptr,
|
|
||||||
connection->read_end - connection->read_ptr);
|
|
||||||
if (nbytes > 0)
|
|
||||||
{
|
|
||||||
size_t total_bytes;
|
|
||||||
|
|
||||||
/* Update read pointer. */
|
|
||||||
connection->read_ptr += nbytes;
|
|
||||||
|
|
||||||
/* Check if we have a complete request header. */
|
|
||||||
total_bytes = connection->read_ptr - connection->read_base;
|
|
||||||
if (total_bytes >= sizeof (request_header))
|
|
||||||
{
|
|
||||||
request_header *header;
|
|
||||||
|
|
||||||
/* Check if we have a complete request. */
|
|
||||||
header = (request_header *)connection->read_base;
|
|
||||||
if (total_bytes >= header->size)
|
|
||||||
{
|
|
||||||
/* Process the request. */
|
|
||||||
if (process_request (connection) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Adjust read pointer, and flush buffer. */
|
|
||||||
connection->read_ptr -= header->size;
|
|
||||||
memmove (connection->read_base,
|
|
||||||
connection->read_base + header->size,
|
|
||||||
connection->read_ptr - connection->read_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes < 0)
|
|
||||||
error (0, errno, _("cannot read from client"));
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Write data to the client on CONNECTION. */
|
|
||||||
int
|
|
||||||
write_data (client_connection *connection)
|
|
||||||
{
|
|
||||||
ssize_t nbytes;
|
|
||||||
|
|
||||||
assert (connection);
|
|
||||||
assert ((connection->write_ptr - connection->write_base) > 0);
|
|
||||||
|
|
||||||
/* Write data. */
|
|
||||||
nbytes = write (connection->sock, connection->write_base,
|
|
||||||
connection->write_ptr - connection->write_base);
|
|
||||||
if (nbytes > 0)
|
|
||||||
{
|
|
||||||
/* Adjust write pointer and flush buffer. */
|
|
||||||
connection->write_ptr -= nbytes;
|
|
||||||
memmove (connection->write_base, connection->write_base + nbytes,
|
|
||||||
connection->write_ptr - connection->write_base);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes < 0)
|
|
||||||
error (0, errno, _("cannot write to client"));
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Process the request received on CONNECTION. Returns 0 if
|
|
||||||
successful, -1 if not. */
|
|
||||||
static int
|
|
||||||
process_request (client_connection *connection)
|
|
||||||
{
|
|
||||||
request_header *header;
|
|
||||||
|
|
||||||
assert (connection);
|
|
||||||
assert (connection->read_base);
|
|
||||||
|
|
||||||
header = (request_header *)connection->read_base;
|
|
||||||
if (header->version != UTMPD_VERSION)
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid protocol version");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (header->type)
|
|
||||||
{
|
|
||||||
case UTMPD_REQ_SETUTENT: return do_setutent (connection);
|
|
||||||
case UTMPD_REQ_GETUTENT: return do_getutent (connection);
|
|
||||||
case UTMPD_REQ_ENDUTENT: return do_endutent (connection);
|
|
||||||
case UTMPD_REQ_GETUTLINE: return do_getutline (connection);
|
|
||||||
case UTMPD_REQ_GETUTID: return do_getutid (connection);
|
|
||||||
case UTMPD_REQ_PUTUTLINE: return do_pututline (connection);
|
|
||||||
case UTMPD_REQ_UPDWTMP: return do_updwtmp (connection);
|
|
||||||
default:
|
|
||||||
warning (EINVAL, "invalid request type");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Send the reply specified by HEADER to the client on CONNECTION.
|
|
||||||
Returns 0 if successful, -1 if not. */
|
|
||||||
static int
|
|
||||||
send_reply (client_connection *connection, const reply_header *reply)
|
|
||||||
{
|
|
||||||
/* Check if the reply fits in the buffer. */
|
|
||||||
if ((size_t) (connection->write_end - connection->write_ptr) < reply->size)
|
|
||||||
{
|
|
||||||
error (0, 0, _("buffer overflow"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy reply to buffer, and adjust write pointer. */
|
|
||||||
memcpy (connection->write_ptr, reply, reply->size);
|
|
||||||
connection->write_ptr += reply->size;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_setutent (client_connection *connection)
|
|
||||||
{
|
|
||||||
setutent_request *request;
|
|
||||||
setutent_reply reply;
|
|
||||||
|
|
||||||
/* The request size varies, so don't check it. */
|
|
||||||
request = (setutent_request *)connection->read_base;
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (setutent_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_SETUTENT;
|
|
||||||
|
|
||||||
/* Select database. */
|
|
||||||
if (!strncmp (request->file, _PATH_UTMP,
|
|
||||||
request->header.size - sizeof (setutent_request)))
|
|
||||||
connection->database = utmp_db;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize position pointer. */
|
|
||||||
connection->position = 0;
|
|
||||||
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
/* Make sure the entry won't match. */
|
|
||||||
connection->last_entry.ut_type = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_getutent (client_connection *connection)
|
|
||||||
{
|
|
||||||
getutent_request *request;
|
|
||||||
getutent_reply reply;
|
|
||||||
|
|
||||||
request = (getutent_request *)connection->read_base;
|
|
||||||
if (request->header.size != sizeof (getutent_request))
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid request size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (getutent_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_GETUTENT;
|
|
||||||
|
|
||||||
if (connection->database == NULL || connection->position == -1)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we're in synch with the ordinary file. */
|
|
||||||
if (synchronize_database (connection->database) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the next entry from the database. */
|
|
||||||
if (read_entry (connection->database, connection->position,
|
|
||||||
&connection->last_entry) < 0)
|
|
||||||
{
|
|
||||||
connection->position = -1;
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update position pointer. */
|
|
||||||
connection->position++;
|
|
||||||
|
|
||||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
return send_reply (connection, (reply_header *)&reply);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_endutent (client_connection *connection)
|
|
||||||
{
|
|
||||||
endutent_request *request;
|
|
||||||
endutent_reply reply;
|
|
||||||
|
|
||||||
request = (endutent_request *)connection->read_base;
|
|
||||||
if (request->header.size != sizeof (endutent_request))
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid request size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deselect database. */
|
|
||||||
connection->database = NULL;
|
|
||||||
|
|
||||||
/* Formulate reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (endutent_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_ENDUTENT;
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_getutline (client_connection *connection)
|
|
||||||
{
|
|
||||||
getutline_request *request;
|
|
||||||
getutline_reply reply;
|
|
||||||
|
|
||||||
request = (getutline_request *)connection->read_base;
|
|
||||||
if (request->header.size != sizeof (getutline_request))
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid request size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (getutline_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_GETUTLINE;
|
|
||||||
|
|
||||||
if (connection->database == NULL || connection->position == -1)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we're in synch with the ordinary file. */
|
|
||||||
if (synchronize_database (connection->database) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* Read the next entry. */
|
|
||||||
if (read_entry (connection->database, connection->position,
|
|
||||||
&connection->last_entry) < 0)
|
|
||||||
{
|
|
||||||
connection->position = -1;
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
connection->position++;
|
|
||||||
|
|
||||||
/* Stop if we found a user or login entry. */
|
|
||||||
if (
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
(connection->last_entry.ut_type == USER_PROCESS
|
|
||||||
|| connection->last_entry.ut_type == LOGIN_PROCESS)
|
|
||||||
&&
|
|
||||||
#endif
|
|
||||||
!strncmp (request->line.ut_line, connection->last_entry.ut_line,
|
|
||||||
sizeof request->line.ut_line))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_getutid (client_connection *connection)
|
|
||||||
{
|
|
||||||
getutid_request *request;
|
|
||||||
getutid_reply reply;
|
|
||||||
|
|
||||||
request = (getutid_request *)connection->read_base;
|
|
||||||
if (request->header.size != sizeof (getutid_request))
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid request size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (getutid_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_GETUTID;
|
|
||||||
|
|
||||||
if (connection->database == NULL || connection->position == -1)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we're in synch with the ordinary file. */
|
|
||||||
if (synchronize_database (connection->database) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (internal_getut_r (connection, &request->id,
|
|
||||||
&connection->last_entry) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_pututline (client_connection *connection)
|
|
||||||
{
|
|
||||||
pututline_request *request;
|
|
||||||
pututline_reply reply;
|
|
||||||
struct utmp buffer;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
request = (pututline_request *)connection->read_base;
|
|
||||||
if (request->header.size != sizeof (pututline_request))
|
|
||||||
{
|
|
||||||
warning (EINVAL, "invalid request size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (pututline_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_PUTUTLINE;
|
|
||||||
|
|
||||||
if (!(connection->access & W_OK))
|
|
||||||
{
|
|
||||||
errno = EPERM;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection->database == NULL)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we're in synch with the ordinary file. */
|
|
||||||
if (synchronize_database (connection->database) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the correct place to insert the data. */
|
|
||||||
if (connection->position > 0
|
|
||||||
&& (
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
(connection->last_entry.ut_type == request->utmp.ut_type
|
|
||||||
&& (connection->last_entry.ut_type == RUN_LVL
|
|
||||||
|| connection->last_entry.ut_type == BOOT_TIME
|
|
||||||
|| connection->last_entry.ut_type == OLD_TIME
|
|
||||||
|| connection->last_entry.ut_type == NEW_TIME))
|
|
||||||
||
|
|
||||||
#endif
|
|
||||||
proc_utmp_eq (&connection->last_entry, &request->utmp)))
|
|
||||||
found = 1;
|
|
||||||
else
|
|
||||||
found = internal_getut_r (connection, &request->utmp, &buffer);
|
|
||||||
|
|
||||||
if (found < 0)
|
|
||||||
{
|
|
||||||
/* We append the next entry. */
|
|
||||||
connection->position =
|
|
||||||
append_entry (connection->database, &request->utmp);
|
|
||||||
if (connection->position < 0)
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* We replace the just read entry. */
|
|
||||||
connection->position--;
|
|
||||||
if (write_entry (connection->database, connection->position,
|
|
||||||
&request->utmp) < 0)
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the entry to the compatibility file. */
|
|
||||||
write_old_entry (connection->database, connection->position, &request->utmp);
|
|
||||||
|
|
||||||
/* Update position pointer. */
|
|
||||||
connection->position++;
|
|
||||||
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
do_updwtmp (client_connection *connection)
|
|
||||||
{
|
|
||||||
updwtmp_request *request;
|
|
||||||
updwtmp_reply reply;
|
|
||||||
utmp_database *database;
|
|
||||||
|
|
||||||
/* The request size varies, so don't check it. */
|
|
||||||
request = (updwtmp_request *)connection->read_base;
|
|
||||||
|
|
||||||
/* Initialize reply. */
|
|
||||||
reply.header.version = UTMPD_VERSION;
|
|
||||||
reply.header.size = sizeof (updwtmp_reply);
|
|
||||||
reply.header.type = UTMPD_REQ_UPDWTMP;
|
|
||||||
|
|
||||||
if (!(connection->access & W_OK))
|
|
||||||
{
|
|
||||||
errno = EPERM;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select database. */
|
|
||||||
if (!strncmp (request->file, _PATH_UTMP,
|
|
||||||
request->header.size - sizeof (updwtmp_request)))
|
|
||||||
database = utmp_db;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we're in synch with the ordinary file. */
|
|
||||||
if (synchronize_database (database) < 0)
|
|
||||||
{
|
|
||||||
errno = ESRCH;
|
|
||||||
goto return_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Append the entry. */
|
|
||||||
if (append_entry (database, &request->utmp) < 0)
|
|
||||||
goto return_error;
|
|
||||||
|
|
||||||
reply.errnum = 0;
|
|
||||||
reply.result = 0;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
|
|
||||||
return_error:
|
|
||||||
reply.errnum = errno;
|
|
||||||
reply.result = -1;
|
|
||||||
return send_reply (connection, &reply.header);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function is identical to the one in login/utmp_file.c. */
|
|
||||||
int
|
|
||||||
proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
(entry->ut_type == INIT_PROCESS
|
|
||||||
|| entry->ut_type == LOGIN_PROCESS
|
|
||||||
|| entry->ut_type == USER_PROCESS
|
|
||||||
|| entry->ut_type == DEAD_PROCESS)
|
|
||||||
&&
|
|
||||||
(match->ut_type == INIT_PROCESS
|
|
||||||
|| match->ut_type == LOGIN_PROCESS
|
|
||||||
|| match->ut_type == USER_PROCESS
|
|
||||||
|| match->ut_type == DEAD_PROCESS)
|
|
||||||
&&
|
|
||||||
#endif
|
|
||||||
#if _HAVE_UT_ID - 0
|
|
||||||
(entry->ut_id[0] && match->ut_id[0]
|
|
||||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
|
||||||
: strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
|
|
||||||
#else
|
|
||||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function is derived from the one in login/utmp_file.c. */
|
|
||||||
static int
|
|
||||||
internal_getut_r (client_connection *connection,
|
|
||||||
const struct utmp *id, struct utmp *buffer)
|
|
||||||
{
|
|
||||||
#if _HAVE_UT_TYPE - 0
|
|
||||||
if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
|
|
||||||
|| id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
|
|
||||||
{
|
|
||||||
/* Search for next entry with type RUN_LVL, BOOT_TIME,
|
|
||||||
OLD_TIME, or NEW_TIME. */
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* Read the next entry. */
|
|
||||||
if (read_entry (connection->database, connection->position,
|
|
||||||
buffer) < 0)
|
|
||||||
{
|
|
||||||
connection->position = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
connection->position++;
|
|
||||||
|
|
||||||
if (id->ut_type == buffer->ut_type)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif /* _HAVE_UT_TYPE */
|
|
||||||
{
|
|
||||||
/* Search for the next entry with the specified ID and with type
|
|
||||||
INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* Read the next entry. */
|
|
||||||
if (read_entry (connection->database, connection->position,
|
|
||||||
buffer) < 0)
|
|
||||||
{
|
|
||||||
connection->position = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
connection->position++;
|
|
||||||
|
|
||||||
if (proc_utmp_eq (buffer, id))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,121 +0,0 @@
|
|||||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utmp.h>
|
|
||||||
|
|
||||||
#include "xtmp.h"
|
|
||||||
|
|
||||||
/* Convert the entry XT to the new utmp format and store it in UT.
|
|
||||||
Fields in UT that were not present in the old utmp format are
|
|
||||||
initialized to zero. */
|
|
||||||
void
|
|
||||||
xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp)
|
|
||||||
{
|
|
||||||
memset (utmp, 0, sizeof (struct utmp));
|
|
||||||
#if _HAVE_XT_TYPE - 0
|
|
||||||
utmp->ut_type = xtmp->xt_type;
|
|
||||||
#endif
|
|
||||||
#if _HAVE_XT_PID - 0
|
|
||||||
utmp->ut_pid = xtmp->xt_pid;
|
|
||||||
#endif
|
|
||||||
strncpy (utmp->ut_line, xtmp->xt_line, XT_LINESIZE);
|
|
||||||
#if _HAVE_XT_ID - 0
|
|
||||||
strncpy (utmp->ut_id, xtmp->xt_id, sizeof xtmp->xt_id);
|
|
||||||
#endif
|
|
||||||
#if _HAVE_UT_TV - 0
|
|
||||||
utmp->ut_tv.tv_sec = xtmp->xt_time;
|
|
||||||
#else
|
|
||||||
utmp->ut_time = xtmp->xt_time;
|
|
||||||
#endif
|
|
||||||
strncpy (utmp->ut_user, xtmp->xt_user, XT_NAMESIZE);
|
|
||||||
#if _HAVE_XT_HOST - 0
|
|
||||||
strncpy (utmp->ut_host, xtmp->xt_host, XT_HOSTSIZE);
|
|
||||||
#endif
|
|
||||||
utmp->ut_addr = xtmp->xt_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the entry UTMP to the old utmp format and store it in XTMP. */
|
|
||||||
void
|
|
||||||
utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp)
|
|
||||||
{
|
|
||||||
memset (xtmp, 0, sizeof (struct xtmp));
|
|
||||||
#if _HAVE_XT_TYPE - 0
|
|
||||||
xtmp->xt_type = utmp->ut_type;
|
|
||||||
#endif
|
|
||||||
#if _HAVE_XT_PID - 0
|
|
||||||
xtmp->xt_pid = utmp->ut_pid;
|
|
||||||
#endif
|
|
||||||
strncpy (xtmp->xt_line, utmp->ut_line, XT_LINESIZE);
|
|
||||||
xtmp->xt_line[XT_LINESIZE] = '\0';
|
|
||||||
#if _HAVE_XT_ID - 0
|
|
||||||
strncpy (xtmp->xt_id, utmp->ut_id, sizeof xtmp->xt_id);
|
|
||||||
#endif
|
|
||||||
#if _HAVE_UT_TV - 0
|
|
||||||
xtmp->xt_time = utmp->ut_tv.tv_sec;
|
|
||||||
#else
|
|
||||||
xtmp->xt_time = utmp->ut_time;
|
|
||||||
#endif
|
|
||||||
strncpy (xtmp->xt_user, utmp->ut_user, XT_NAMESIZE);
|
|
||||||
#if _HAVE_XT_HOST - 0
|
|
||||||
strncpy (xtmp->xt_host, utmp->ut_host, XT_HOSTSIZE);
|
|
||||||
xtmp->xt_host[XT_HOSTSIZE] = '\0';
|
|
||||||
#endif
|
|
||||||
xtmp->xt_addr = utmp->ut_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compare an old style entry XTMP with a new style entry UTMP. The
|
|
||||||
function returns 1 if the information that is in both old and new
|
|
||||||
style entries is identical. Otherwise this function returns 0.
|
|
||||||
|
|
||||||
The type of the argument `xtmp' is `struct utmp *', not `struct
|
|
||||||
utmp *'. This is intentional! We convert from and to `struct
|
|
||||||
xtmp' directly when we read and write an old style entry. But
|
|
||||||
since XTMP is converted from an old style entry, we compare only
|
|
||||||
those elements of the structure that are common to both the new and
|
|
||||||
the old style entry. */
|
|
||||||
int
|
|
||||||
compare_entry (const struct utmp *xtmp, const struct utmp *utmp)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(
|
|
||||||
#if _HAVE_XT_TYPE - 0
|
|
||||||
xtmp->ut_type == utmp->ut_type
|
|
||||||
#endif
|
|
||||||
#if _HAVE_XT_PID - 0
|
|
||||||
&& xtmp->ut_pid == utmp->ut_pid
|
|
||||||
#endif
|
|
||||||
&& !strncmp (xtmp->ut_line, utmp->ut_line, XT_LINESIZE - 1)
|
|
||||||
#if _HAVE_XT_ID - 0
|
|
||||||
&& !strncmp (xtmp->ut_id, utmp->ut_id, sizeof utmp->ut_id)
|
|
||||||
#endif
|
|
||||||
#if _HAVE_UT_TV - 0
|
|
||||||
&& xtmp->ut_tv.tv_sec == utmp->ut_tv.tv_sec
|
|
||||||
#else
|
|
||||||
&& xtmp->ut_time == utmp->ut_time
|
|
||||||
#endif
|
|
||||||
&& !strncmp (xtmp->ut_user, utmp->ut_user, XT_NAMESIZE)
|
|
||||||
#if _HAVE_XT_HOST - 0
|
|
||||||
&& !strncmp (xtmp->ut_host, utmp->ut_host, XT_HOSTSIZE - 1)
|
|
||||||
#endif
|
|
||||||
&& xtmp->ut_addr == utmp->ut_addr);
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/* The `struct xtmp' type, describing the old linux utmp format.
|
|
||||||
Copyright (C) 1997 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
#ifndef _XTMP_H
|
|
||||||
#define _XTMP_H 1
|
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define XT_LINESIZE 12
|
|
||||||
#define XT_NAMESIZE 8
|
|
||||||
#define XT_HOSTSIZE 16
|
|
||||||
|
|
||||||
struct xtmp
|
|
||||||
{
|
|
||||||
short int xt_type; /* Type of login. */
|
|
||||||
pid_t xt_pid; /* Pid of login process. */
|
|
||||||
char xt_line[XT_LINESIZE]; /* NUL-terminated devicename of tty. */
|
|
||||||
char xt_id[4]; /* Inittab id. */
|
|
||||||
time_t xt_time; /* Time entry was made. */
|
|
||||||
char xt_user[XT_NAMESIZE]; /* Username (not NUL terminated). */
|
|
||||||
char xt_host[XT_HOSTSIZE]; /* Hostname for remote login. */
|
|
||||||
long xt_addr; /* Internet address of remote host. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define _HAVE_XT_TYPE 1
|
|
||||||
#define _HAVE_XT_PID 1
|
|
||||||
#define _HAVE_XT_ID 1
|
|
||||||
#define _HAVE_XT_HOST 1
|
|
||||||
|
|
||||||
|
|
||||||
extern void xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp);
|
|
||||||
extern void utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp);
|
|
||||||
extern int compare_entry (const struct utmp *xtmp,
|
|
||||||
const struct utmp *utmp);
|
|
||||||
|
|
||||||
#endif /* xtmp.h */
|
|
Loading…
Reference in New Issue
Block a user