From b13927da591adbbae887fc89cc66c8ca7ab5b13b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 3 Jun 1997 21:53:09 +0000 Subject: Update. 1997-06-03 23:42 Ulrich Drepper * elf/dl-support.c: Define and initialize _dl_verbose used in dl-machine.h. * io/ftw.c: Expand stat/lstat calls. * manual/intro.texi: Also refer to ISO 9945. Update info about SVID. Add description for XPG. * md5-crypt/md5-crypt.c: Namespace cleanups. * md5-crypt/md5.c: Likewise. * md5-crypt/md5.h: Likewise. * sysdeps/generic/crypt-entry.c: Likewise. * posix/unistd.h (_POSIX2_C_VERSION): Set to 199209L. * stdlib/fmtmsg.h: Declare addseverity only if __USE_SVID is defined. * sunrpc/rpc_scan.c (findkind): Declare `token' as const. * sunrpc/rpc_util.c (toktostr): Declare `token' as const. * time/Makefile: Make tzselect dependen of config.make. 1997-06-01 15:01 Miles Bader * manual/string.texi (String and Array Utilities): Add `Argz and Envz Vectors' to the menu. (Argz and Envz Vectors, Argz Functions, Envz Functions): New nodes. 1997-05-31 20:59 Andreas Schwab * login/Makefile (utmpd-routines): Add utmpd. (extra-objs): Add utmpd objects to get dependencies. (distribute): Add sources for utmpd. (subdir-dirs): Define. 1997-06-02 16:28 Ulrich Drepper * sysdeps/wordsize-32/inttypes.h: Include features.h and use __CONCAT instead of defined __CONCAT__ ourself. * sysdeps/wordsize-64/inttypes.h: Likewise. 1997-06-01 19:11 Andreas Schwab * sysdeps/wordsize-64/inttypes.h (INTMAX_C): Use `l' suffix, not `ll'. (PRIdFAST, PRIoFAST, PRIxFAST, PRIuFAST, SCNdFAST, SCNiFAST, SCNoFAST, SCNxFAST): Correct format specifiers. 1997-06-02 04:23 Ulrich Drepper * sysdeps/unix/syscalls.list: Make fchdir weak alias for __fchdir. 1997-06-01 19:17 Ulrich Drepper * md5-crypt/Makefile: Correct libmd5crypt file to really generate DES free libcrypt. * md5-crypt/onlymd5-entry.c: New file. Wrapper around sysdeps/generic/crypt-entry.c. 1997-06-01 12:48 Ulrich Drepper * sysdeps/unix/sysv/linux/alpha/gnu/types.h (__fd_mask): Change type to `unsigned long int'. Patch by Richard Henderson . 1997-05-30 17:34 Andreas Jaeger * sysdeps/generic/bb_init_func.c (__bb_init_func): Use ISO C declaration style. * nss/nss_files/files-hosts.c: Delete inclusion of "../resolv/mapv4v6hostent.h". --- login/Makefile | 9 +- login/programs/connection.c | 180 ++++++++++++ login/programs/database.c | 516 ++++++++++++++++++++++++++++++++ login/programs/error.c | 104 +++++++ login/programs/request.c | 650 +++++++++++++++++++++++++++++++++++++++++ login/programs/utmpd-private.h | 107 +++++++ login/programs/utmpd.c | 384 ++++++++++++++++++++++++ login/programs/utmpd.h | 141 +++++++++ login/programs/utmpdump.c | 53 ++++ login/programs/xtmp.c | 102 +++++++ login/programs/xtmp.h | 56 ++++ login/utmpd/connection.c | 180 ------------ login/utmpd/database.c | 516 -------------------------------- login/utmpd/error.c | 104 ------- login/utmpd/request.c | 650 ----------------------------------------- login/utmpd/utmpd-private.h | 107 ------- login/utmpd/utmpd.c | 384 ------------------------ login/utmpd/utmpd.h | 141 --------- login/utmpd/xtmp.c | 102 ------- login/utmpd/xtmp.h | 56 ---- login/utmpdump.c | 53 ---- 21 files changed, 2299 insertions(+), 2296 deletions(-) create mode 100644 login/programs/connection.c create mode 100644 login/programs/database.c create mode 100644 login/programs/error.c create mode 100644 login/programs/request.c create mode 100644 login/programs/utmpd-private.h create mode 100644 login/programs/utmpd.c create mode 100644 login/programs/utmpd.h create mode 100644 login/programs/utmpdump.c create mode 100644 login/programs/xtmp.c create mode 100644 login/programs/xtmp.h delete mode 100644 login/utmpd/connection.c delete mode 100644 login/utmpd/database.c delete mode 100644 login/utmpd/error.c delete mode 100644 login/utmpd/request.c delete mode 100644 login/utmpd/utmpd-private.h delete mode 100644 login/utmpd/utmpd.c delete mode 100644 login/utmpd/utmpd.h delete mode 100644 login/utmpd/xtmp.c delete mode 100644 login/utmpd/xtmp.h delete mode 100644 login/utmpdump.c (limited to 'login') diff --git a/login/Makefile b/login/Makefile index 832b1ca..05913ee 100644 --- a/login/Makefile +++ b/login/Makefile @@ -29,11 +29,14 @@ routines := getutent getutent_r getutid getutline getutid_r getutline_r \ others = utmpd install-sbin = utmpd -utmpd-routines := connection database error request xtmp +utmpd-routines := utmpd connection database error request xtmp +extra-objs := $(utmpd-routines:=.o) -distribute := utmp-private.h utmpd/xtmp.h utmpd/utmpd.h utmpd/utmpd-private.h +distribute := utmp-private.h programs/xtmp.h programs/utmpd.h \ + programs/utmpd-private.h $(utmpd-routines:%=programs/%.c) -vpath %.c utmpd +subdir-dirs = programs +vpath %.c programs # Build the -lutil library with these extra functions. extra-libs := libutil diff --git a/login/programs/connection.c b/login/programs/connection.c new file mode 100644 index 0000000..4e16631 --- /dev/null +++ b/login/programs/connection.c @@ -0,0 +1,180 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include +#include + +#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); +} diff --git a/login/programs/database.c b/login/programs/database.c new file mode 100644 index 0000000..e31e0d9 --- /dev/null +++ b/login/programs/database.c @@ -0,0 +1,516 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 proc_utmp_eq (const struct utmp *entry, const struct utmp *match); +static int get_mtime (const char *file, 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) +{ + utmp_database *database; + + /* Allocate memory. */ + database = (utmp_database *) malloc (sizeof (utmp_database)); + if (database == NULL) + return NULL; + + memset (database, 0, sizeof (utmp_database)); + + /* Open database. */ + database->fd = open (file, O_RDWR); + if (database->fd < 0) + goto fail; + + database->old_fd = open (old_file, O_RDWR); + if (database->old_fd < 0) + goto fail; + + if ((file && !(database->file = strdup (file))) + || (old_file && !(database->old_file = strdup (old_file)))) + goto fail; + + if (initialize_database (database) < 0 + || synchronize_database (database) < 0) + goto fail; + + return database; + +fail: + 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_file, &mtime) < 0) + 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) + 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) + return -1; + } + else +#endif + { + if (store_process_entry (database, position, &entry) < 0) + return -1; + } + + /* Update position. */ + position++; + } + + while (1) + { + if (read_entry (database, position, &entry) < 0) + break; + + if (write_old_entry (database, position, &entry) < 0) + return -1; + + /* Update position. */ + position++; + } + } + + return 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 (old_entry->ut_time > new_entry.ut_time) + 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 +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 (old_entry->ut_time > new_entry.ut_time) + 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; +} + + +/* This function is identical to the one in login/utmp_file.c. */ +static 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 + strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 +#else + strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 +#endif + ); +} + + +/* Get modification time of FILE and put it in TIMER. returns 0 if + successful, -1 if not. */ +static int +get_mtime (const char *file, time_t *timer) +{ + struct stat st; + + if (stat (file, &st) < 0) + return -1; + + *timer = st.st_mtime; + + return 0; +} diff --git a/login/programs/error.c b/login/programs/error.c new file mode 100644 index 0000000..e651144 --- /dev/null +++ b/login/programs/error.c @@ -0,0 +1,104 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include +#include + +#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); +} diff --git a/login/programs/request.c b/login/programs/request.c new file mode 100644 index 0000000..0f68b8a --- /dev/null +++ b/login/programs/request.c @@ -0,0 +1,650 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include + +#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 proc_utmp_eq (const struct utmp *entry, const struct utmp *match); +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; + + request = (setutent_request *)connection->read_base; + if (request->header.size != sizeof (setutent_request)) + { + warning (EINVAL, "invalid request size"); + return -1; + } + + /* 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, sizeof request->file)) + 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 || 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; + } + + /* 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; + + request = (updwtmp_request *)connection->read_base; + if (request->header.size != sizeof (updwtmp_request)) + { + warning (EINVAL, "invalid request size"); + return -1; + } + + /* 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, sizeof request->file)) + 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. */ +static 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 + strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 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; +} diff --git a/login/programs/utmpd-private.h b/login/programs/utmpd-private.h new file mode 100644 index 0000000..4a9cdb9 --- /dev/null +++ b/login/programs/utmpd-private.h @@ -0,0 +1,107 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 _UTMPD_PRIVATE_H +#define _UTMPD_PRIVATE_H 1 + +#include +#include + + +/* The number of connections we allow. */ +#ifndef MAX_CONNECTIONS +#define MAX_CONNECTIONS 16 +#endif + + +typedef struct utmp_database +{ + int fd; + int old_fd; + char *file; + char *old_file; + time_t mtime; +} utmp_database; + + +/* The databases we handle. */ +extern utmp_database *utmp_db; +extern utmp_database *wtmp_db; + + +typedef struct client_connection +{ + int sock; + /* Access permissions. */ + int access; + + /* Read pointer. */ + void *read_base; + void *read_ptr; + void *read_end; + + /* Write buffer. */ + void *write_base; + void *write_ptr; + void *write_end; + + /* Database to use for this connection. */ + utmp_database *database; + /* Position pointer. */ + int position; + + /* Last read entry. */ + struct utmp last_entry; + + /* Pointers to the next and previous connections in the list. */ + struct client_connection *next; + struct client_connection *prev; +} client_connection; + + +/* 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. */ +extern int forked; + + +/* Database functions. */ +utmp_database *open_database (const char *file, const char *old_file); +int synchronize_database (utmp_database *database); +void close_database (utmp_database *database); +int read_entry (utmp_database *database, int position, struct utmp *entry); +int write_entry (utmp_database *database, int position, + const struct utmp *entry); +int append_entry (utmp_database *database, const struct utmp *entry); +int read_old_entry (utmp_database *database, int position, struct utmp *entry); +int write_old_entry (utmp_database *database, int position, + const struct utmp *entry); + +/* Connection oriented functions. */ +client_connection *accept_connection (int sock, int access); +client_connection *find_connection (int sock); +void close_connection (client_connection *connection); +int read_data (client_connection *connection); +int write_data (client_connection *connection); + +void error (int status, int errnum, const char *message, ...); +void warning (int errnum, const char *message, ...); + +#endif /* utmpd-private.h */ + diff --git a/login/programs/utmpd.c b/login/programs/utmpd.c new file mode 100644 index 0000000..e112181 --- /dev/null +++ b/login/programs/utmpd.c @@ -0,0 +1,384 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utmpd.h" +#include "utmpd-private.h" + +/* Get libc version number. */ +#include "../../version.h" + +#define PACKAGE "libc" + +/* Long options. */ +static const struct option long_options[] = +{ + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0} +}; + +/* The UTMP database. */ +utmp_database *utmp_db; + +/* The socket for read only requests. */ +int ro_sock = -1; + +/* The socket for read/write requests. */ +int rw_sock = -1; + + +/* Prototypes for the local functions. */ +static void usage (int status) __attribute__ ((noreturn)); +static void drop_priviliges (void); +static int make_socket (const char *name); +static void handle_requests (void) __attribute__ ((noreturn)); +static void termination_handler (int signum); +static int check_pid (const char *file); +static int write_pid (const char *file); + + +int +main (int argc, char *argv[]) +{ + mode_t mask; + int debug; + int do_help; + int do_version; + int opt; + + /* Initialize local variables. */ + debug = 0; + do_help = 0; + do_version = 0; + + while ((opt = getopt_long (argc, argv, "dhV", long_options, NULL)) != -1) + switch (opt) + { + case '\0': /* Long option. */ + break; + case 'h': + do_help = 1; + break; + case 'd': + debug = 1; + break; + case 'V': + do_version = 1; + break; + default: + usage (EXIT_FAILURE); + } + + /* Version information is reequested. */ + if (do_version) + { + printf ("utmpd (GNU %s) %s\n", PACKAGE, VERSION); + printf (gettext ("\ +Copyright (C) %s Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "1997"); + printf (gettext ("Written by %s.\n"), "Mark Kettenis"); + + exit (EXIT_SUCCESS); + } + + /* Help is requested. */ + if (do_help) + usage (EXIT_SUCCESS); + + signal (SIGINT, termination_handler); + signal (SIGTERM, termination_handler); + + /* Check if we are already running. */ + if (check_pid (_PATH_UTMPDPID)) + error (EXIT_FAILURE, 0, "already running"); + + /* Open UTMP database. */ + utmp_db = open_database (_PATH_UTMP "x", _PATH_UTMP); + if (utmp_db == NULL) + error (EXIT_FAILURE, errno, "%s", _PATH_UTMP); + + /* Create sockets, with the right permissions. */ + mask = umask (S_IXUSR | S_IXGRP | S_IXOTH); + ro_sock = make_socket (_PATH_UTMPD_RO); + umask (S_IXUSR | S_IRWXG | S_IRWXO); + rw_sock = make_socket (_PATH_UTMPD_RW); + umask (mask); + + /* Set the sockets up to accept connections. */ + if (listen (ro_sock, MAX_CONNECTIONS) < 0 + || listen (rw_sock, MAX_CONNECTIONS) < 0) + error (EXIT_FAILURE, errno, "cannot enable socket to accept connections"); + + /* Behave like a daemon. */ + if (!debug) + { + openlog ("utmpd", LOG_CONS | LOG_ODELAY, LOG_DAEMON); + + if (daemon (0, 0) < 0) + error (EXIT_FAILURE, errno, "cannot auto-background"); + forked = 1; + + if (write_pid (_PATH_UTMPDPID) < 0) + warning (errno, "%s", _PATH_UTMPDPID); + } + + /* Drop priviliges. */ + drop_priviliges (); + + /* Handle incoming requests. */ + handle_requests (); +} + + +/* Display usage information and exit. */ +static void +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, gettext ("Try `%s --help' for more information.\n"), + program_invocation_name); + else + { + printf (gettext ("\ +Usage: %s [OPTION]...\n\ + -d, --debug do not fork and display messages on the current tty\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n"), + program_invocation_name); + fputs (gettext ("\ +Report bugs to .\n"), + stdout); + } + + exit (status); +} + + +/* Drop priviliges. */ +static void +drop_priviliges (void) +{ + struct passwd *pw; + + pw = getpwnam ("daemon"); + if (pw) + { + seteuid (pw->pw_uid); + setegid (pw->pw_gid); + } +} + + +/* Make a socket in the file namespace using the filename NAME as the + socket's address. */ +static int +make_socket (const char *name) +{ + struct sockaddr_un addr; + size_t size; + int sock; + + /* Create the socket. */ + sock = socket (PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + error (EXIT_FAILURE, errno, "cannot create socket"); + + /* Bind a name to the socket. */ + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, name); + + /* The size of the address is the offset of the start + of the filename, plus its length, plus one for the + terminating null byte. */ + size = (offsetof (struct sockaddr_un, sun_path) + + strlen (addr.sun_path)); + + if (bind (sock, (struct sockaddr *) &addr, size) < 0) + error (EXIT_FAILURE, errno, "%s", name); + + return sock; +} + + +/* Hanlde incoming requests. */ +static +void handle_requests (void) +{ + client_connection *connection; + fd_set active_read_fd_set; + fd_set active_write_fd_set; + fd_set read_fd_set; + fd_set write_fd_set; + int fd; + + /* Initialize the set of active sockets. */ + FD_ZERO (&active_read_fd_set); + FD_ZERO (&active_write_fd_set); + FD_SET (rw_sock, &active_read_fd_set); + FD_SET (ro_sock, &active_read_fd_set); + + while (1) + { + /* Block until input arrives on one or more active sockets. */ + read_fd_set = active_read_fd_set; + write_fd_set = active_write_fd_set; + if (select (FD_SETSIZE, &read_fd_set, &write_fd_set, NULL, NULL) < 0) + error (EXIT_FAILURE, errno, "cannot get input on sockets"); + + /* Service all the sockets with input pending. */ + for (fd = 0; fd < FD_SETSIZE; fd++) + { + if (FD_ISSET (fd, &read_fd_set)) + { + if (fd == ro_sock || fd == rw_sock) + { + int access = ((fd == rw_sock) ? (R_OK | W_OK) : R_OK); + + connection = accept_connection (fd, access); + if (connection == NULL) + error (0, errno, "cannot accept connection"); + + FD_SET (connection->sock, &active_read_fd_set); + } + else + { + connection = find_connection (fd); + if (connection == NULL) + error (EXIT_FAILURE, 0, "cannot find connection"); + + if (read_data (connection) < 0) + { + close_connection (connection); + FD_CLR (fd, &active_read_fd_set); + FD_CLR (fd, &active_write_fd_set); + } + + if (connection->write_ptr > connection->write_base) + FD_SET (fd, &active_write_fd_set); + } + } + if (FD_ISSET (fd, &write_fd_set) && + fd != rw_sock && fd != ro_sock) + { + connection = find_connection (fd); + if (connection == NULL) + error (EXIT_FAILURE, 0, "cannot find connection"); + + if (write_data (connection) < 0) + { + close_connection (connection); + FD_CLR (fd, &active_read_fd_set); + FD_CLR (fd, &active_write_fd_set); + } + + if (connection->write_ptr == connection->write_base) + FD_CLR (fd, &active_write_fd_set); + } + } + } +} + + +/* Cleanup. */ +static void +termination_handler (int signum) +{ + /* Close sockets. */ + close (ro_sock); + close (rw_sock); + + /* Restore user id. */ + seteuid (getuid ()); + + /* Clean up the files created by `bind'. */ + unlink (_PATH_UTMPD_RO); + unlink (_PATH_UTMPD_RW); + + if (utmp_db) + close_database (utmp_db); + + /* Clean up pid file. */ + unlink (_PATH_UTMPDPID); + + exit (EXIT_SUCCESS); +} + + +/* Returns 1 if the process in pid file FILE is running, 0 if not. */ +static int +check_pid (const char *file) +{ + FILE *fp; + + fp = fopen (_PATH_UTMPDPID, "r"); + if (fp) + { + pid_t pid; + + fscanf (fp, "%d", &pid); + fclose (fp); + + if (kill (pid, 0) == 0) + return 1; + } + + return 0; +} + +/* Write the current process id to the file FILE. Returns 0 if + successful, -1 if not. */ +static int +write_pid (const char *file) +{ + FILE *fp; + + fp = fopen (_PATH_UTMPDPID, "w"); + if (fp == NULL) + return -1; + + fprintf (fp, "%d\n", getpid ()); + if (ferror (fp)) + return -1; + + fclose (fp); + + return 0; +} + diff --git a/login/programs/utmpd.h b/login/programs/utmpd.h new file mode 100644 index 0000000..8fbc33c --- /dev/null +++ b/login/programs/utmpd.h @@ -0,0 +1,141 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 _UTMPD_H +#define _UTMPD_H 1 + +/* This is an *internal* header. */ + +#include +#include +#include + + +/* Paths to daemon sockets. */ +#define _PATH_UTMPD_RO "/var/run/utmpd.ro" +#define _PATH_UTMPD_RW "/var/run/utmpd.rw" + + +/* Path to PID file. */ +#define _PATH_UTMPDPID "/var/run/utmpd.pid" + + +/* Version number of the daemon interface. */ +#define UTMPD_VERSION 1 + + +/* Services provided. */ +typedef enum +{ + UTMPD_REQ_SETUTENT, + UTMPD_REQ_GETUTENT, + UTMPD_REQ_ENDUTENT, + UTMPD_REQ_GETUTLINE, + UTMPD_REQ_GETUTID, + UTMPD_REQ_PUTUTLINE, + UTMPD_REQ_UPDWTMP +} request_type; + + +/* Header common to all requests. */ +typedef struct +{ + /* Version number of the daemon interface. */ + int version; + /* Number of bytes in this request. */ + size_t size; + /* Service requested. */ + request_type type; +} request_header; + +typedef struct +{ + request_header header; + /* File to use. */ + char file[_POSIX_PATH_MAX + 1]; +} setutent_request; + +typedef struct +{ + request_header header; +} getutent_request, endutent_request; + +typedef struct +{ + request_header header; + /* Entry to match. */ + struct utmp line; +} getutline_request; + +typedef struct +{ + request_header header; + /* Entry to match. */ + struct utmp id; +} getutid_request; + +typedef struct +{ + request_header header; + /* Entry to write. */ + struct utmp utmp; +} pututline_request; + +typedef struct +{ + request_header header; + /* File to use. */ + char file[_POSIX_PATH_MAX + 1]; + /* Entry to write. */ + struct utmp utmp; +} updwtmp_request; + + +/* Header common to all replies. */ +typedef struct +{ + /* Version number of the daemon interface. */ + int version; + /* Number of bytes in this reply. */ + size_t size; + /* Answer to the request. */ + request_type type; +} reply_header; + +typedef struct +{ + reply_header header; + /* Error code. */ + int errnum; + /* Return value. */ + int result; +} setutent_reply, endutent_reply, pututline_reply, updwtmp_reply; + +typedef struct +{ + reply_header header; + /* Found entry. */ + struct utmp entry; + /* Error code. */ + int errnum; + /* Return value. */ + int result; +} getutent_reply, getutline_reply, getutid_reply; + +#endif /* utmpd.h */ diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c new file mode 100644 index 0000000..e1422b5 --- /dev/null +++ b/login/programs/utmpdump.c @@ -0,0 +1,53 @@ +/* utmpdump - dump utmp-like files. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include +#include +#include + +void +print_entry (struct utmp *up) +{ + printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s] [%ld]\n", + up->ut_type, up->ut_pid, up->ut_id, up->ut_user, + up->ut_line, 4 + ctime (&up->ut_time), up->ut_tv.tv_usec); +} + +int +main (int argc, char *argv[]) +{ + struct utmp *up; + + if (argc > 1) + utmpname (argv[1]); + + setutent (); + + while ((up = getutent ())) + print_entry (up); + + endutent (); + + return EXIT_SUCCESS; +} diff --git a/login/programs/xtmp.c b/login/programs/xtmp.c new file mode 100644 index 0000000..d2d5fee --- /dev/null +++ b/login/programs/xtmp.c @@ -0,0 +1,102 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Mark Kettenis , 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 +#include +#include +#include +#include + +#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 + utmp->ut_time = xtmp->xt_time; + 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 + xtmp->xt_time = utmp->ut_time; + 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. */ +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 + && xtmp->ut_time == utmp->ut_time + && !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); +} diff --git a/login/programs/xtmp.h b/login/programs/xtmp.h new file mode 100644 index 0000000..8fa982e --- /dev/null +++ b/login/programs/xtmp.h @@ -0,0 +1,56 @@ +/* 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 , 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 + +#include +#include + + +#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 adress 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 */ diff --git a/login/utmpd/connection.c b/login/utmpd/connection.c deleted file mode 100644 index 4e16631..0000000 --- a/login/utmpd/connection.c +++ /dev/null @@ -1,180 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include -#include - -#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); -} diff --git a/login/utmpd/database.c b/login/utmpd/database.c deleted file mode 100644 index e31e0d9..0000000 --- a/login/utmpd/database.c +++ /dev/null @@ -1,516 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include -#include -#include -#include -#include - - -#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 proc_utmp_eq (const struct utmp *entry, const struct utmp *match); -static int get_mtime (const char *file, 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) -{ - utmp_database *database; - - /* Allocate memory. */ - database = (utmp_database *) malloc (sizeof (utmp_database)); - if (database == NULL) - return NULL; - - memset (database, 0, sizeof (utmp_database)); - - /* Open database. */ - database->fd = open (file, O_RDWR); - if (database->fd < 0) - goto fail; - - database->old_fd = open (old_file, O_RDWR); - if (database->old_fd < 0) - goto fail; - - if ((file && !(database->file = strdup (file))) - || (old_file && !(database->old_file = strdup (old_file)))) - goto fail; - - if (initialize_database (database) < 0 - || synchronize_database (database) < 0) - goto fail; - - return database; - -fail: - 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_file, &mtime) < 0) - 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) - 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) - return -1; - } - else -#endif - { - if (store_process_entry (database, position, &entry) < 0) - return -1; - } - - /* Update position. */ - position++; - } - - while (1) - { - if (read_entry (database, position, &entry) < 0) - break; - - if (write_old_entry (database, position, &entry) < 0) - return -1; - - /* Update position. */ - position++; - } - } - - return 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 (old_entry->ut_time > new_entry.ut_time) - 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 -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 (old_entry->ut_time > new_entry.ut_time) - 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; -} - - -/* This function is identical to the one in login/utmp_file.c. */ -static 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 - strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 -#else - strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 -#endif - ); -} - - -/* Get modification time of FILE and put it in TIMER. returns 0 if - successful, -1 if not. */ -static int -get_mtime (const char *file, time_t *timer) -{ - struct stat st; - - if (stat (file, &st) < 0) - return -1; - - *timer = st.st_mtime; - - return 0; -} diff --git a/login/utmpd/error.c b/login/utmpd/error.c deleted file mode 100644 index e651144..0000000 --- a/login/utmpd/error.c +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include -#include - -#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); -} diff --git a/login/utmpd/request.c b/login/utmpd/request.c deleted file mode 100644 index 0f68b8a..0000000 --- a/login/utmpd/request.c +++ /dev/null @@ -1,650 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include - -#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 proc_utmp_eq (const struct utmp *entry, const struct utmp *match); -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; - - request = (setutent_request *)connection->read_base; - if (request->header.size != sizeof (setutent_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* 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, sizeof request->file)) - 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 || 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; - } - - /* 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; - - request = (updwtmp_request *)connection->read_base; - if (request->header.size != sizeof (updwtmp_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* 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, sizeof request->file)) - 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. */ -static 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 - strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 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; -} diff --git a/login/utmpd/utmpd-private.h b/login/utmpd/utmpd-private.h deleted file mode 100644 index 4a9cdb9..0000000 --- a/login/utmpd/utmpd-private.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 _UTMPD_PRIVATE_H -#define _UTMPD_PRIVATE_H 1 - -#include -#include - - -/* The number of connections we allow. */ -#ifndef MAX_CONNECTIONS -#define MAX_CONNECTIONS 16 -#endif - - -typedef struct utmp_database -{ - int fd; - int old_fd; - char *file; - char *old_file; - time_t mtime; -} utmp_database; - - -/* The databases we handle. */ -extern utmp_database *utmp_db; -extern utmp_database *wtmp_db; - - -typedef struct client_connection -{ - int sock; - /* Access permissions. */ - int access; - - /* Read pointer. */ - void *read_base; - void *read_ptr; - void *read_end; - - /* Write buffer. */ - void *write_base; - void *write_ptr; - void *write_end; - - /* Database to use for this connection. */ - utmp_database *database; - /* Position pointer. */ - int position; - - /* Last read entry. */ - struct utmp last_entry; - - /* Pointers to the next and previous connections in the list. */ - struct client_connection *next; - struct client_connection *prev; -} client_connection; - - -/* 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. */ -extern int forked; - - -/* Database functions. */ -utmp_database *open_database (const char *file, const char *old_file); -int synchronize_database (utmp_database *database); -void close_database (utmp_database *database); -int read_entry (utmp_database *database, int position, struct utmp *entry); -int write_entry (utmp_database *database, int position, - const struct utmp *entry); -int append_entry (utmp_database *database, const struct utmp *entry); -int read_old_entry (utmp_database *database, int position, struct utmp *entry); -int write_old_entry (utmp_database *database, int position, - const struct utmp *entry); - -/* Connection oriented functions. */ -client_connection *accept_connection (int sock, int access); -client_connection *find_connection (int sock); -void close_connection (client_connection *connection); -int read_data (client_connection *connection); -int write_data (client_connection *connection); - -void error (int status, int errnum, const char *message, ...); -void warning (int errnum, const char *message, ...); - -#endif /* utmpd-private.h */ - diff --git a/login/utmpd/utmpd.c b/login/utmpd/utmpd.c deleted file mode 100644 index e112181..0000000 --- a/login/utmpd/utmpd.c +++ /dev/null @@ -1,384 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utmpd.h" -#include "utmpd-private.h" - -/* Get libc version number. */ -#include "../../version.h" - -#define PACKAGE "libc" - -/* Long options. */ -static const struct option long_options[] = -{ - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0} -}; - -/* The UTMP database. */ -utmp_database *utmp_db; - -/* The socket for read only requests. */ -int ro_sock = -1; - -/* The socket for read/write requests. */ -int rw_sock = -1; - - -/* Prototypes for the local functions. */ -static void usage (int status) __attribute__ ((noreturn)); -static void drop_priviliges (void); -static int make_socket (const char *name); -static void handle_requests (void) __attribute__ ((noreturn)); -static void termination_handler (int signum); -static int check_pid (const char *file); -static int write_pid (const char *file); - - -int -main (int argc, char *argv[]) -{ - mode_t mask; - int debug; - int do_help; - int do_version; - int opt; - - /* Initialize local variables. */ - debug = 0; - do_help = 0; - do_version = 0; - - while ((opt = getopt_long (argc, argv, "dhV", long_options, NULL)) != -1) - switch (opt) - { - case '\0': /* Long option. */ - break; - case 'h': - do_help = 1; - break; - case 'd': - debug = 1; - break; - case 'V': - do_version = 1; - break; - default: - usage (EXIT_FAILURE); - } - - /* Version information is reequested. */ - if (do_version) - { - printf ("utmpd (GNU %s) %s\n", PACKAGE, VERSION); - printf (gettext ("\ -Copyright (C) %s Free Software Foundation, Inc.\n\ -This is free software; see the source for copying conditions. There is NO\n\ -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "1997"); - printf (gettext ("Written by %s.\n"), "Mark Kettenis"); - - exit (EXIT_SUCCESS); - } - - /* Help is requested. */ - if (do_help) - usage (EXIT_SUCCESS); - - signal (SIGINT, termination_handler); - signal (SIGTERM, termination_handler); - - /* Check if we are already running. */ - if (check_pid (_PATH_UTMPDPID)) - error (EXIT_FAILURE, 0, "already running"); - - /* Open UTMP database. */ - utmp_db = open_database (_PATH_UTMP "x", _PATH_UTMP); - if (utmp_db == NULL) - error (EXIT_FAILURE, errno, "%s", _PATH_UTMP); - - /* Create sockets, with the right permissions. */ - mask = umask (S_IXUSR | S_IXGRP | S_IXOTH); - ro_sock = make_socket (_PATH_UTMPD_RO); - umask (S_IXUSR | S_IRWXG | S_IRWXO); - rw_sock = make_socket (_PATH_UTMPD_RW); - umask (mask); - - /* Set the sockets up to accept connections. */ - if (listen (ro_sock, MAX_CONNECTIONS) < 0 - || listen (rw_sock, MAX_CONNECTIONS) < 0) - error (EXIT_FAILURE, errno, "cannot enable socket to accept connections"); - - /* Behave like a daemon. */ - if (!debug) - { - openlog ("utmpd", LOG_CONS | LOG_ODELAY, LOG_DAEMON); - - if (daemon (0, 0) < 0) - error (EXIT_FAILURE, errno, "cannot auto-background"); - forked = 1; - - if (write_pid (_PATH_UTMPDPID) < 0) - warning (errno, "%s", _PATH_UTMPDPID); - } - - /* Drop priviliges. */ - drop_priviliges (); - - /* Handle incoming requests. */ - handle_requests (); -} - - -/* Display usage information and exit. */ -static void -usage (int status) -{ - if (status != EXIT_SUCCESS) - fprintf (stderr, gettext ("Try `%s --help' for more information.\n"), - program_invocation_name); - else - { - printf (gettext ("\ -Usage: %s [OPTION]...\n\ - -d, --debug do not fork and display messages on the current tty\n\ - -h, --help display this help and exit\n\ - -V, --version output version information and exit\n"), - program_invocation_name); - fputs (gettext ("\ -Report bugs to .\n"), - stdout); - } - - exit (status); -} - - -/* Drop priviliges. */ -static void -drop_priviliges (void) -{ - struct passwd *pw; - - pw = getpwnam ("daemon"); - if (pw) - { - seteuid (pw->pw_uid); - setegid (pw->pw_gid); - } -} - - -/* Make a socket in the file namespace using the filename NAME as the - socket's address. */ -static int -make_socket (const char *name) -{ - struct sockaddr_un addr; - size_t size; - int sock; - - /* Create the socket. */ - sock = socket (PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - error (EXIT_FAILURE, errno, "cannot create socket"); - - /* Bind a name to the socket. */ - addr.sun_family = AF_UNIX; - strcpy (addr.sun_path, name); - - /* The size of the address is the offset of the start - of the filename, plus its length, plus one for the - terminating null byte. */ - size = (offsetof (struct sockaddr_un, sun_path) - + strlen (addr.sun_path)); - - if (bind (sock, (struct sockaddr *) &addr, size) < 0) - error (EXIT_FAILURE, errno, "%s", name); - - return sock; -} - - -/* Hanlde incoming requests. */ -static -void handle_requests (void) -{ - client_connection *connection; - fd_set active_read_fd_set; - fd_set active_write_fd_set; - fd_set read_fd_set; - fd_set write_fd_set; - int fd; - - /* Initialize the set of active sockets. */ - FD_ZERO (&active_read_fd_set); - FD_ZERO (&active_write_fd_set); - FD_SET (rw_sock, &active_read_fd_set); - FD_SET (ro_sock, &active_read_fd_set); - - while (1) - { - /* Block until input arrives on one or more active sockets. */ - read_fd_set = active_read_fd_set; - write_fd_set = active_write_fd_set; - if (select (FD_SETSIZE, &read_fd_set, &write_fd_set, NULL, NULL) < 0) - error (EXIT_FAILURE, errno, "cannot get input on sockets"); - - /* Service all the sockets with input pending. */ - for (fd = 0; fd < FD_SETSIZE; fd++) - { - if (FD_ISSET (fd, &read_fd_set)) - { - if (fd == ro_sock || fd == rw_sock) - { - int access = ((fd == rw_sock) ? (R_OK | W_OK) : R_OK); - - connection = accept_connection (fd, access); - if (connection == NULL) - error (0, errno, "cannot accept connection"); - - FD_SET (connection->sock, &active_read_fd_set); - } - else - { - connection = find_connection (fd); - if (connection == NULL) - error (EXIT_FAILURE, 0, "cannot find connection"); - - if (read_data (connection) < 0) - { - close_connection (connection); - FD_CLR (fd, &active_read_fd_set); - FD_CLR (fd, &active_write_fd_set); - } - - if (connection->write_ptr > connection->write_base) - FD_SET (fd, &active_write_fd_set); - } - } - if (FD_ISSET (fd, &write_fd_set) && - fd != rw_sock && fd != ro_sock) - { - connection = find_connection (fd); - if (connection == NULL) - error (EXIT_FAILURE, 0, "cannot find connection"); - - if (write_data (connection) < 0) - { - close_connection (connection); - FD_CLR (fd, &active_read_fd_set); - FD_CLR (fd, &active_write_fd_set); - } - - if (connection->write_ptr == connection->write_base) - FD_CLR (fd, &active_write_fd_set); - } - } - } -} - - -/* Cleanup. */ -static void -termination_handler (int signum) -{ - /* Close sockets. */ - close (ro_sock); - close (rw_sock); - - /* Restore user id. */ - seteuid (getuid ()); - - /* Clean up the files created by `bind'. */ - unlink (_PATH_UTMPD_RO); - unlink (_PATH_UTMPD_RW); - - if (utmp_db) - close_database (utmp_db); - - /* Clean up pid file. */ - unlink (_PATH_UTMPDPID); - - exit (EXIT_SUCCESS); -} - - -/* Returns 1 if the process in pid file FILE is running, 0 if not. */ -static int -check_pid (const char *file) -{ - FILE *fp; - - fp = fopen (_PATH_UTMPDPID, "r"); - if (fp) - { - pid_t pid; - - fscanf (fp, "%d", &pid); - fclose (fp); - - if (kill (pid, 0) == 0) - return 1; - } - - return 0; -} - -/* Write the current process id to the file FILE. Returns 0 if - successful, -1 if not. */ -static int -write_pid (const char *file) -{ - FILE *fp; - - fp = fopen (_PATH_UTMPDPID, "w"); - if (fp == NULL) - return -1; - - fprintf (fp, "%d\n", getpid ()); - if (ferror (fp)) - return -1; - - fclose (fp); - - return 0; -} - diff --git a/login/utmpd/utmpd.h b/login/utmpd/utmpd.h deleted file mode 100644 index 8fbc33c..0000000 --- a/login/utmpd/utmpd.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 _UTMPD_H -#define _UTMPD_H 1 - -/* This is an *internal* header. */ - -#include -#include -#include - - -/* Paths to daemon sockets. */ -#define _PATH_UTMPD_RO "/var/run/utmpd.ro" -#define _PATH_UTMPD_RW "/var/run/utmpd.rw" - - -/* Path to PID file. */ -#define _PATH_UTMPDPID "/var/run/utmpd.pid" - - -/* Version number of the daemon interface. */ -#define UTMPD_VERSION 1 - - -/* Services provided. */ -typedef enum -{ - UTMPD_REQ_SETUTENT, - UTMPD_REQ_GETUTENT, - UTMPD_REQ_ENDUTENT, - UTMPD_REQ_GETUTLINE, - UTMPD_REQ_GETUTID, - UTMPD_REQ_PUTUTLINE, - UTMPD_REQ_UPDWTMP -} request_type; - - -/* Header common to all requests. */ -typedef struct -{ - /* Version number of the daemon interface. */ - int version; - /* Number of bytes in this request. */ - size_t size; - /* Service requested. */ - request_type type; -} request_header; - -typedef struct -{ - request_header header; - /* File to use. */ - char file[_POSIX_PATH_MAX + 1]; -} setutent_request; - -typedef struct -{ - request_header header; -} getutent_request, endutent_request; - -typedef struct -{ - request_header header; - /* Entry to match. */ - struct utmp line; -} getutline_request; - -typedef struct -{ - request_header header; - /* Entry to match. */ - struct utmp id; -} getutid_request; - -typedef struct -{ - request_header header; - /* Entry to write. */ - struct utmp utmp; -} pututline_request; - -typedef struct -{ - request_header header; - /* File to use. */ - char file[_POSIX_PATH_MAX + 1]; - /* Entry to write. */ - struct utmp utmp; -} updwtmp_request; - - -/* Header common to all replies. */ -typedef struct -{ - /* Version number of the daemon interface. */ - int version; - /* Number of bytes in this reply. */ - size_t size; - /* Answer to the request. */ - request_type type; -} reply_header; - -typedef struct -{ - reply_header header; - /* Error code. */ - int errnum; - /* Return value. */ - int result; -} setutent_reply, endutent_reply, pututline_reply, updwtmp_reply; - -typedef struct -{ - reply_header header; - /* Found entry. */ - struct utmp entry; - /* Error code. */ - int errnum; - /* Return value. */ - int result; -} getutent_reply, getutline_reply, getutid_reply; - -#endif /* utmpd.h */ diff --git a/login/utmpd/xtmp.c b/login/utmpd/xtmp.c deleted file mode 100644 index d2d5fee..0000000 --- a/login/utmpd/xtmp.c +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include - -#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 - utmp->ut_time = xtmp->xt_time; - 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 - xtmp->xt_time = utmp->ut_time; - 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. */ -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 - && xtmp->ut_time == utmp->ut_time - && !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); -} diff --git a/login/utmpd/xtmp.h b/login/utmpd/xtmp.h deleted file mode 100644 index 8fa982e..0000000 --- a/login/utmpd/xtmp.h +++ /dev/null @@ -1,56 +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 , 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 - -#include -#include - - -#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 adress 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 */ diff --git a/login/utmpdump.c b/login/utmpdump.c deleted file mode 100644 index e1422b5..0000000 --- a/login/utmpdump.c +++ /dev/null @@ -1,53 +0,0 @@ -/* utmpdump - dump utmp-like files. - Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 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 -#include -#include -#include -#include -#include -#include - -void -print_entry (struct utmp *up) -{ - printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s] [%ld]\n", - up->ut_type, up->ut_pid, up->ut_id, up->ut_user, - up->ut_line, 4 + ctime (&up->ut_time), up->ut_tv.tv_usec); -} - -int -main (int argc, char *argv[]) -{ - struct utmp *up; - - if (argc > 1) - utmpname (argv[1]); - - setutent (); - - while ((up = getutent ())) - print_entry (up); - - endutent (); - - return EXIT_SUCCESS; -} -- cgit v1.1