lib/, src/, configure.ac: Use utmpx instead of utmp

utmpx is specified by POSIX as an XSI extension.  That's more portable
than utmp, which is unavailable for example in musl libc.  The manual
page specifies that in Linux (but it probably means in glibc), utmp and
utmpx (and the functions that use them) are identical, so this commit
shouldn't affect glibc systems.

Assume utmpx is always present.

Also, if utmpx is present, POSIX guarantees that some members exist:

-  ut_user
-  ut_id
-  ut_line
-  ut_pid
-  ut_type
-  ut_tv

So, rely on them unconditionally.

Fixes: 170b76cdd1 ("Disable utmpx permanently")
Closes: <https://github.com/shadow-maint/shadow/issues/945>
Reported-by: Firas Khalil Khana <firasuke@gmail.com>
Reported-by: "A. Wilfox" <https://github.com/awilfox>
Tested-by: Firas Khalil Khana <firasuke@gmail.com>
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This commit is contained in:
Alejandro Colomar
2024-02-17 15:15:38 +01:00
parent 4d139ca466
commit 64bcb54fa9
5 changed files with 97 additions and 97 deletions

View File

@@ -49,7 +49,7 @@ AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
AC_CHECK_FUNCS(arc4random_buf futimes \
getentropy getrandom getspnam getusershell \
initgroups lckpwdf lutimes \
setgroups updwtmp updwtmpx innetgr \
setgroups updwtmpx innetgr \
getspnam_r \
rpmatch \
memset_explicit explicit_bzero stpecpy stpeprintf)
@@ -57,17 +57,13 @@ AC_SYS_LARGEFILE
dnl Checks for typedefs, structures, and compiler characteristics.
AC_CHECK_MEMBERS([struct utmp.ut_type,
struct utmp.ut_id,
struct utmp.ut_name,
struct utmp.ut_user,
struct utmp.ut_host,
struct utmp.ut_syslen,
struct utmp.ut_addr,
struct utmp.ut_addr_v6,
struct utmp.ut_time,
struct utmp.ut_xtime,
struct utmp.ut_tv],,,[[#include <utmp.h>]])
AC_CHECK_MEMBERS([struct utmpx.ut_name,
struct utmpx.ut_host,
struct utmpx.ut_syslen,
struct utmpx.ut_addr,
struct utmpx.ut_addr_v6,
struct utmpx.ut_time,
struct utmpx.ut_xtime],,,[[#include <utmpx.h>]])
dnl Checks for library functions.
AC_TYPE_GETGROUPS

View File

@@ -28,7 +28,7 @@
*
* A "last login" entry is created for the user being logged in. The
* UID is extracted from the global (struct passwd) entry and the
* TTY information is gotten from the (struct utmp).
* TTY information is gotten from the (struct utmpx).
*/
void dolastlog (
struct lastlog *ll,

View File

@@ -51,13 +51,15 @@ int user_busy (const char *name, uid_t uid)
#endif /* !__linux__ */
}
#ifndef __linux__
static int user_busy_utmp (const char *name)
{
struct utmp *utent;
setutent ();
while ((utent = getutent ()) != NULL)
#ifndef __linux__
static int
user_busy_utmp(const char *name)
{
struct utmpx *utent;
setutxent();
while ((utent = getutxent()) != NULL)
{
if (utent->ut_type != USER_PROCESS) {
continue;
@@ -79,6 +81,7 @@ static int user_busy_utmp (const char *name)
}
#endif /* !__linux__ */
#ifdef __linux__
#ifdef ENABLE_SUBIDS
#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range)

View File

@@ -13,7 +13,7 @@
#include "prototypes.h"
#include "getdef.h"
#include <utmp.h>
#include <utmpx.h>
#include <assert.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -59,13 +59,15 @@ static bool is_my_tty (const char tty[UT_LINESIZE])
return strcmp (full_tty, tmptty) == 0;
}
/*
* failtmp - update the cumulative failure log
*
* failtmp updates the (struct utmp) formatted failure log which
* failtmp updates the (struct utmpx) formatted failure log which
* maintains a record of all login failures.
*/
static void failtmp (const char *username, const struct utmp *failent)
static void
failtmp(const char *username, const struct utmpx *failent)
{
const char *ftmp;
int fd;
@@ -121,6 +123,7 @@ err_close:
username, ftmp));
}
/*
* get_current_utmp - return the most probable utmp entry for the current
* session
@@ -129,52 +132,51 @@ err_close:
* The line entered by the *getty / telnetd, etc. should also match
* the current terminal.
*
* When an entry is returned by get_current_utmp, and if the utmp
* When an entry is returned by get_current_utmp, and if the utmpx
* structure has a ut_id field, this field should be used to update
* the entry information.
*
* Return NULL if no entries exist in utmp for the current process.
*/
static
/*@null@*/ /*@only@*/struct utmp *get_current_utmp (void)
static /*@null@*/ /*@only@*/struct utmpx *
get_current_utmp(void)
{
struct utmp *ut;
struct utmp *ret = NULL;
struct utmpx *ut;
struct utmpx *ret = NULL;
setutent ();
setutxent();
/* First, try to find a valid utmp entry for this process. */
while ((ut = getutent ()) != NULL) {
while ((ut = getutxent()) != NULL) {
if ( (ut->ut_pid == getpid ())
#ifdef HAVE_STRUCT_UTMP_UT_ID
&& ('\0' != ut->ut_id[0])
#endif
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
&& ( (LOGIN_PROCESS == ut->ut_type)
|| (USER_PROCESS == ut->ut_type))
#endif
/* A process may have failed to close an entry
* Check if this entry refers to the current tty */
&& is_my_tty (ut->ut_line)) {
&& is_my_tty(ut->ut_line))
{
break;
}
}
if (NULL != ut) {
ret = XMALLOC(1, struct utmp);
ret = XMALLOC(1, struct utmpx);
memcpy (ret, ut, sizeof (*ret));
}
endutent ();
endutxent();
return ret;
}
int get_session_host (char **out)
int
get_session_host(char **out)
{
char *hostname = NULL;
struct utmp *ut = NULL;
int ret = 0;
int ret = 0;
char *hostname;
struct utmpx *ut;
ut = get_current_utmp();
@@ -196,13 +198,15 @@ int get_session_host (char **out)
return ret;
}
#ifndef USE_PAM
/*
* Some systems already have updwtmp() and possibly updwtmpx(). Others
* Some systems already have updwtmpx(). Others
* don't, so we re-implement these functions if necessary.
*/
#ifndef HAVE_UPDWTMP
static void updwtmp (const char *filename, const struct utmp *ut)
#ifndef HAVE_UPDWTMPX
static void
updwtmpx(const char *filename, const struct utmpx *ut)
{
int fd;
@@ -212,8 +216,7 @@ static void updwtmp (const char *filename, const struct utmp *ut)
close (fd);
}
}
#endif /* ! HAVE_UPDWTMP */
#endif /* ! HAVE_UPDWTMPX */
#endif /* ! USE_PAM */
@@ -235,15 +238,13 @@ static void updwtmp (const char *filename, const struct utmp *ut)
*
* The returned structure shall be freed by the caller.
*/
static
/*@only@*/struct utmp *prepare_utmp (const char *name,
const char *line,
const char *host,
/*@null@*/const struct utmp *ut)
static /*@only@*/struct utmpx *
prepare_utmp(const char *name, const char *line, const char *host,
/*@null@*/const struct utmpx *ut)
{
struct timeval tv;
char *hostname = NULL;
struct utmp *utent;
char *hostname = NULL;
struct utmpx *utent;
struct timeval tv;
assert (NULL != name);
assert (NULL != line);
@@ -267,28 +268,22 @@ static
}
utent = XCALLOC (1, struct utmp);
utent = XCALLOC(1, struct utmpx);
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
utent->ut_type = USER_PROCESS;
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
utent->ut_pid = getpid ();
STRNCPY(utent->ut_line, line);
#ifdef HAVE_STRUCT_UTMP_UT_ID
if (NULL != ut) {
STRNCPY(utent->ut_id, ut->ut_id);
} else {
/* XXX - assumes /dev/tty?? */
STRNCPY(utent->ut_id, line + 3);
}
#endif /* HAVE_STRUCT_UTMP_UT_ID */
#ifdef HAVE_STRUCT_UTMP_UT_NAME
STRNCPY(utent->ut_name, name);
#endif /* HAVE_STRUCT_UTMP_UT_NAME */
#ifdef HAVE_STRUCT_UTMP_UT_USER
STRNCPY(utent->ut_user, name);
#endif /* HAVE_STRUCT_UTMP_UT_USER */
if (NULL != hostname) {
struct addrinfo *info = NULL;
#ifdef HAVE_STRUCT_UTMP_UT_HOST
@@ -340,45 +335,45 @@ static
#ifdef HAVE_STRUCT_UTMP_UT_XTIME
utent->ut_xtime = tv.tv_usec;
#endif /* HAVE_STRUCT_UTMP_UT_XTIME */
#ifdef HAVE_STRUCT_UTMP_UT_TV
utent->ut_tv.tv_sec = tv.tv_sec;
utent->ut_tv.tv_usec = tv.tv_usec;
#endif /* HAVE_STRUCT_UTMP_UT_TV */
}
return utent;
}
/*
* setutmp - Update an entry in utmp and log an entry in wtmp
*
* Return 1 on failure and 0 on success.
*/
static int setutmp (struct utmp *ut)
static int
setutmp(struct utmpx *ut)
{
int err = 0;
assert (NULL != ut);
setutent ();
if (pututline (ut) == NULL) {
setutxent();
if (pututxline(ut) == NULL) {
err = 1;
}
endutent ();
endutxent();
#ifndef USE_PAM
/* This is done by pam_lastlog */
updwtmp (_WTMP_FILE, ut);
updwtmpx(_WTMP_FILE, ut);
#endif /* ! USE_PAM */
return err;
}
int update_utmp (const char *user,
const char *tty,
const char *host)
int
update_utmp(const char *user, const char *tty, const char *host)
{
struct utmp *utent, *ut;
struct utmpx *utent, *ut;
utent = get_current_utmp ();
ut = prepare_utmp (user, tty, host, utent);
@@ -391,11 +386,11 @@ int update_utmp (const char *user,
return 0;
}
void record_failure(const char *failent_user,
const char *tty,
const char *hostname)
void
record_failure(const char *failent_user, const char *tty, const char *hostname)
{
struct utmp *utent, *failent;
struct utmpx *utent, *failent;
if (getdef_str ("FTMP_FILE") != NULL) {
utent = get_current_utmp ();
@@ -406,13 +401,15 @@ void record_failure(const char *failent_user,
}
}
unsigned long active_sessions_count(const char *name, unsigned long limit)
{
struct utmp *ut;
unsigned long count = 0;
setutent ();
while ((ut = getutent ()))
unsigned long
active_sessions_count(const char *name, unsigned long limit)
{
struct utmpx *ut;
unsigned long count = 0;
setutxent();
while ((ut = getutxent()))
{
if (USER_PROCESS != ut->ut_type) {
continue;
@@ -428,7 +425,7 @@ unsigned long active_sessions_count(const char *name, unsigned long limit)
break;
}
}
endutent ();
endutxent();
return count;
}

View File

@@ -15,7 +15,7 @@
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <utmp.h>
#include <utmpx.h>
#include "defines.h"
#include "prototypes.h"
#include "shadowlog.h"
@@ -34,14 +34,17 @@ const char *Prog;
#define HUP_MESG_FILE "/etc/logoutd.mesg"
#endif
/* local function prototypes */
static int check_login (const struct utmp *ut);
static int check_login (const struct utmpx *ut);
static void send_mesg_to_tty (int tty_fd);
/*
* check_login - check if user (struct utmp) allowed to stay logged in
* check_login - check if user (struct utmpx) allowed to stay logged in
*/
static int check_login (const struct utmp *ut)
static int
check_login(const struct utmpx *ut)
{
char user[sizeof(ut->ut_user) + 1];
char line[sizeof(ut->ut_line) + 1];
@@ -112,16 +115,17 @@ static void send_mesg_to_tty (int tty_fd)
* utmp file is periodically scanned and offending users are logged
* off from the system.
*/
int main (int argc, char **argv)
int
main(int argc, char **argv)
{
int i;
int status;
pid_t pid;
int i;
int status;
pid_t pid;
struct utmp *ut;
char user[sizeof (ut->ut_user) + 1]; /* terminating NUL */
char tty_name[sizeof (ut->ut_line) + 6]; /* /dev/ + NUL */
int tty_fd;
struct utmpx *ut;
char user[sizeof (ut->ut_user) + 1]; /* terminating NUL */
char tty_name[sizeof (ut->ut_line) + 6]; /* /dev/ + NUL */
int tty_fd;
if (1 != argc) {
(void) fputs (_("Usage: logoutd\n"), stderr);
@@ -169,14 +173,14 @@ int main (int argc, char **argv)
* Attempt to re-open the utmp file. The file is only
* open while it is being used.
*/
setutent ();
setutxent();
/*
* Read all of the entries in the utmp file. The entries
* for login sessions will be checked to see if the user
* is permitted to be signed on at this time.
*/
while ((ut = getutent ()) != NULL) {
while ((ut = getutxent()) != NULL) {
if (ut->ut_type != USER_PROCESS) {
continue;
}
@@ -238,7 +242,7 @@ int main (int argc, char **argv)
exit (EXIT_SUCCESS);
}
endutent ();
endutxent();
#ifndef DEBUG
sleep (60);