* libmisc/utmp.c: Reworked. Get rid of Linux specific stuff. Get rid
of global utent/utxent variables. Only reuse the ut_id and maybe the ut_host fields from utmp. * lib/prototypes.h, libmisc/utmp.c: Removed checkutmp(), setutmp(), setutmpx(). * lib/prototypes.h, libmisc/utmp.c: Added get_current_utmp(), prepare_utmp(), prepare_utmpx(), setutmp(), setutmpx(). * libmisc/utmp.c (is_my_tty): Only compare the name of the utmp line with ttyname(). (No stat of the two terminals to compare the devices). * libmisc/utmp.c: Use getaddrinfo() to get the address of the host. * configure.in: Check for getaddrinfo(). * configure.in: Use AC_CHECK_MEMBERS to check for the existence of fields in the utmp/utmpx structures. * configure.in: Reject systems with utmpx support but no ut_id field in utmp. This could be fixed later if needed. * src/login.c: Use the new utmp functions. This also simplifies the failtmp() handling. * src/login.c: passwd_free() renamed to pw_free() and shadow_free() renamed to spw_free()
This commit is contained in:
parent
fcfa81283e
commit
82c1a583f8
54
configure.in
54
configure.in
@ -41,7 +41,7 @@ AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
|
||||
AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
|
||||
gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
|
||||
lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r)
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
@ -59,37 +59,31 @@ AC_CHECK_MEMBERS([struct stat.st_mtimensec])
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
if test "$ac_cv_header_utmp_h" = "yes"; then
|
||||
AC_CACHE_CHECK(for ut_host in struct utmp,
|
||||
ac_cv_struct_utmp_ut_host,
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <utmp.h>],
|
||||
[struct utmp ut; char *cp = ut.ut_host;]
|
||||
)],
|
||||
[ac_cv_struct_utmp_ut_host=yes],
|
||||
[ac_cv_struct_utmp_ut_host=no]
|
||||
)
|
||||
)
|
||||
|
||||
if test "$ac_cv_struct_utmp_ut_host" = "yes"; then
|
||||
AC_DEFINE(UT_HOST, 1, [Define if you have ut_host in struct utmp.])
|
||||
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>]])
|
||||
dnl There are dependencies:
|
||||
dnl If UTMPX has to be used, the utmp structure shall have a ut_id field.
|
||||
if test "$ac_cv_header_utmpx_h" = "yes" &&
|
||||
test "$ac_cv_member_struct_utmp_ut_id" != "yes"; then
|
||||
AC_MSG_ERROR(Systems with UTMPX and no ut_id field in the utmp structure are not supported)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for ut_user in struct utmp,
|
||||
ac_cv_struct_utmp_ut_user,
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <utmp.h>],
|
||||
[struct utmp ut; char *cp = ut.ut_user;]
|
||||
)],
|
||||
[ac_cv_struct_utmp_ut_user=yes],
|
||||
[ac_cv_struct_utmp_ut_user=no]
|
||||
)
|
||||
)
|
||||
|
||||
if test "$ac_cv_struct_utmp_ut_user" = "no"; then
|
||||
AC_DEFINE(ut_user, ut_name,
|
||||
[Define to ut_name if struct utmp has ut_name (not ut_user).])
|
||||
fi
|
||||
fi
|
||||
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>]])
|
||||
|
||||
if test "$ac_cv_header_lastlog_h" = "yes"; then
|
||||
AC_CACHE_CHECK(for ll_host in struct lastlog,
|
||||
|
@ -345,8 +345,19 @@ extern char *tz (const char *);
|
||||
extern int set_filesize_limit (int blocks);
|
||||
|
||||
/* utmp.c */
|
||||
extern void checkutmp (bool picky);
|
||||
extern int setutmp (const char *, const char *, const char *);
|
||||
extern struct utmp *get_current_utmp (void);
|
||||
extern struct utmp *prepare_utmp (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
struct utmp *ut);
|
||||
extern int setutmp (struct utmp *ut);
|
||||
#ifdef HAVE_UTMPX_H
|
||||
extern struct utmpx *prepare_utmpx (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
struct utmp *ut);
|
||||
extern int setutmpx (struct utmpx *utx);
|
||||
#endif
|
||||
|
||||
/* valid.c */
|
||||
extern bool valid (const char *, const struct passwd *);
|
||||
|
603
libmisc/utmp.c
603
libmisc/utmp.c
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -37,24 +37,19 @@
|
||||
|
||||
#include <utmp.h>
|
||||
|
||||
// FIXME: disable UTMPX on Linux in configure.in
|
||||
// Maybe define an intermediate USE_UTMPX to replace HAVE_UTMPX_H,
|
||||
// which would be defined if HAVE_UTMPX_H is defined on non-Linux.
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
struct utmpx utxent;
|
||||
#endif
|
||||
struct utmp utent;
|
||||
|
||||
#define NO_UTENT \
|
||||
_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")
|
||||
#define NO_TTY \
|
||||
_("Unable to determine your tty name.")
|
||||
|
||||
/*
|
||||
* is_my_tty -- determine if "tty" is the same TTY stdin is using
|
||||
@ -62,19 +57,21 @@ struct utmp utent;
|
||||
static bool is_my_tty (const char *tty)
|
||||
{
|
||||
char full_tty[200];
|
||||
struct stat by_name, by_fd;
|
||||
static const char *tmptty = NULL;
|
||||
|
||||
if ('/' != *tty) {
|
||||
snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
|
||||
tty = full_tty;
|
||||
}
|
||||
|
||||
if ( (stat (tty, &by_name) != 0)
|
||||
|| (fstat (STDIN_FILENO, &by_fd) != 0)) {
|
||||
return false;
|
||||
if (NULL == tmptty) {
|
||||
tmptty = ttyname (STDIN_FILENO);
|
||||
}
|
||||
|
||||
if (by_name.st_rdev != by_fd.st_rdev) {
|
||||
if (NULL == tmptty) {
|
||||
(void) puts (_("Unable to determine your tty name."));
|
||||
exit (EXIT_FAILURE);
|
||||
} else if (strcmp (tty, tmptty) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -82,36 +79,36 @@ static bool is_my_tty (const char *tty)
|
||||
}
|
||||
|
||||
/*
|
||||
* checkutmp - see if utmp file is correct for this process
|
||||
* get_current_utmp - return the most probable utmp entry for the current
|
||||
* session
|
||||
*
|
||||
* System V is very picky about the contents of the utmp file
|
||||
* and requires that a slot for the current process exist.
|
||||
* The utmp file is scanned for an entry with the same process
|
||||
* ID. If no entry exists the process exits with a message.
|
||||
* The utmp file is scanned for an entry with the same process ID.
|
||||
* The line enterred by the *getty / telnetd, etc. should also match
|
||||
* the current terminal.
|
||||
*
|
||||
* The "picky" flag is for network and other logins that may
|
||||
* use special flags. It allows the pid checks to be overridden.
|
||||
* This means that getty should never invoke login with any
|
||||
* command line flags.
|
||||
* When an entry is returned by get_current_utmp, and if the utmp
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) /* XXX */
|
||||
|
||||
void checkutmp (bool picky)
|
||||
struct utmp *get_current_utmp (void)
|
||||
{
|
||||
char *line;
|
||||
struct utmp *ut;
|
||||
pid_t pid = getpid ();
|
||||
struct utmp *ret = NULL;
|
||||
|
||||
setutent ();
|
||||
|
||||
/* First, try to find a valid utmp entry for this process. */
|
||||
while ((ut = getutent ()) != NULL) {
|
||||
if ( (ut->ut_pid == pid)
|
||||
&& ('\0' != ut->ut_line[0])
|
||||
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)) {
|
||||
@ -119,173 +116,20 @@ void checkutmp (bool picky)
|
||||
}
|
||||
}
|
||||
|
||||
/* We cannot trust the ut_line field. Prepare the new value. */
|
||||
line = ttyname (0);
|
||||
if (NULL == line) {
|
||||
(void) puts (NO_TTY);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
/* If there is one, just use it, otherwise create a new one. */
|
||||
if (NULL != ut) {
|
||||
utent = *ut;
|
||||
} else {
|
||||
if (picky) {
|
||||
(void) puts (NO_UTENT);
|
||||
exit (EXIT_FAILURE);
|
||||
ret = malloc (sizeof (*ret));
|
||||
memcpy (ret, ut, sizeof (*ret));
|
||||
}
|
||||
memset ((void *) &utent, 0, sizeof utent);
|
||||
utent.ut_type = LOGIN_PROCESS;
|
||||
utent.ut_pid = pid;
|
||||
/* XXX - assumes /dev/tty?? or /dev/pts/?? */
|
||||
strncpy (utent.ut_id, line + 3, sizeof utent.ut_id);
|
||||
strcpy (utent.ut_user, "LOGIN");
|
||||
utent.ut_time = time (NULL);
|
||||
}
|
||||
|
||||
/* Sanitize / set the ut_line field */
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
|
||||
endutent ();
|
||||
}
|
||||
|
||||
#elif defined(LOGIN_PROCESS)
|
||||
|
||||
void checkutmp (bool picky)
|
||||
{
|
||||
char *line;
|
||||
struct utmp *ut;
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
struct utmpx *utx;
|
||||
#endif
|
||||
pid_t pid = getpid ();
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
setutxent ();
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (picky) {
|
||||
#if HAVE_UTMPX_H
|
||||
while ((utx = getutxent ()) != NULL) {
|
||||
if (utx->ut_pid == pid) {
|
||||
break;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != utx) {
|
||||
utxent = *utx;
|
||||
}
|
||||
#endif
|
||||
while ((ut = getutent ()) != NULL) {
|
||||
if (ut->ut_pid == pid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != ut) {
|
||||
utent = *ut;
|
||||
}
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
endutxent ();
|
||||
#endif
|
||||
endutent ();
|
||||
|
||||
if (NULL == ut) {
|
||||
(void) puts (NO_UTENT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#ifndef UNIXPC
|
||||
|
||||
/*
|
||||
* If there is no ut_line value in this record, fill
|
||||
* it in by getting the TTY name and stuffing it in
|
||||
* the structure. The UNIX/PC is broken in this regard
|
||||
* and needs help ...
|
||||
*/
|
||||
/* XXX: The ut_line may not match with the current tty.
|
||||
* ut_line will be set by setutmp anyway, but ut_id
|
||||
* will not be set, and the wrong utmp entry may be
|
||||
* updated. -- nekral */
|
||||
|
||||
if (utent.ut_line[0] == '\0')
|
||||
#endif /* !UNIXPC */
|
||||
{
|
||||
line = ttyname (0);
|
||||
if (NULL == line) {
|
||||
(void) puts (NO_TTY);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
#if HAVE_UTMPX_H
|
||||
strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
line = ttyname (0);
|
||||
if (NULL == line) {
|
||||
(void) puts (NO_TTY);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
ut = getutline (&utent);
|
||||
if (NULL != ut) {
|
||||
strncpy (utent.ut_id, ut->ut_id, sizeof ut->ut_id);
|
||||
}
|
||||
|
||||
strcpy (utent.ut_user, "LOGIN");
|
||||
utent.ut_pid = getpid ();
|
||||
utent.ut_type = LOGIN_PROCESS;
|
||||
utent.ut_time = time (NULL);
|
||||
#if HAVE_UTMPX_H
|
||||
strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
|
||||
utx = getutxline (&utxent);
|
||||
if (NULL != utx) {
|
||||
strncpy (utxent.ut_id, utx->ut_id, sizeof utxent.ut_id);
|
||||
}
|
||||
|
||||
strcpy (utxent.ut_user, "LOGIN");
|
||||
utxent.ut_pid = utent.ut_pid;
|
||||
utxent.ut_type = utent.ut_type;
|
||||
if (sizeof (utxent.ut_tv) == sizeof (struct timeval)) {
|
||||
gettimeofday ((struct timeval *) &utxent.ut_tv, NULL);
|
||||
} else {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
utxent.ut_tv.tv_sec = tv.tv_sec;
|
||||
utxent.ut_tv.tv_usec = tv.tv_usec;
|
||||
}
|
||||
utent.ut_time = utxent.ut_tv.tv_sec;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
endutxent ();
|
||||
#endif
|
||||
endutent ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Some systems already have updwtmp() and possibly updwtmpx(). Others
|
||||
* don't, so we re-implement these functions if necessary. --marekm
|
||||
* don't, so we re-implement these functions if necessary.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UPDWTMP
|
||||
static void updwtmp (const char *filename, const struct utmp *ut)
|
||||
{
|
||||
@ -319,140 +163,293 @@ static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
* setutmp - put a USER_PROCESS entry in the utmp file
|
||||
*
|
||||
* setutmp changes the type of the current utmp entry to
|
||||
* USER_PROCESS. the wtmp file will be updated as well.
|
||||
* USER_PROCESS.
|
||||
* The wtmp file will be updated as well.
|
||||
*
|
||||
* ut, as returned by get_current_utmp
|
||||
*
|
||||
* We reuse the ut_id and ut_host fields
|
||||
*
|
||||
* The returned structure shall be freed by the caller.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) /* XXX */
|
||||
|
||||
int setutmp (const char *name, const char unused(*line), const char unused(*host))
|
||||
{
|
||||
int err = 0;
|
||||
utent.ut_type = USER_PROCESS;
|
||||
strncpy (utent.ut_user, name, sizeof utent.ut_user);
|
||||
utent.ut_time = time (NULL);
|
||||
/* other fields already filled in by checkutmp above */
|
||||
setutent ();
|
||||
if (pututline (&utent) == NULL) {
|
||||
err = 1;
|
||||
}
|
||||
endutent ();
|
||||
updwtmp (_WTMP_FILE, &utent);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#elif HAVE_UTMPX_H
|
||||
|
||||
int setutmp (const char *name, const char *line, const char *host)
|
||||
{
|
||||
struct utmp *utmp, utline;
|
||||
struct utmpx *utmpx, utxline;
|
||||
pid_t pid = getpid ();
|
||||
bool found_utmpx = false;
|
||||
bool found_utmp = false;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* The canonical device name doesn't include "/dev/"; skip it
|
||||
* if it is already there.
|
||||
* prepare_utmp - prepare an utmp entry so that it can be logged in a
|
||||
* utmp/wtmp file.
|
||||
*
|
||||
* It requires an utmp entry in input (ut) to return an entry with
|
||||
* the right ut_id. This is typically an entry returned by
|
||||
* get_current_utmp
|
||||
*
|
||||
* The ut_host field of the input structure may also be kept, and to
|
||||
* define the ut_addr/ut_addr_v6 fields. (if these fields exist)
|
||||
*
|
||||
* Other fields are discarded and filed with new values (if they
|
||||
* exist).
|
||||
*
|
||||
* The returned structure shall be freed by the caller.
|
||||
*/
|
||||
struct utmp *prepare_utmp (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
struct utmp *ut)
|
||||
{
|
||||
struct timeval tv;
|
||||
char *hostname = NULL;
|
||||
struct utmp *utent;
|
||||
|
||||
assert (NULL != name);
|
||||
assert (NULL != line);
|
||||
assert (NULL != ut);
|
||||
|
||||
|
||||
|
||||
if ( (NULL != host)
|
||||
&& ('\0' != host)) {
|
||||
hostname = (char *) xmalloc (strlen (host) + 1);
|
||||
strcpy (hostname, host);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
} else if ( (NULL != ut->ut_host)
|
||||
&& ('\0' != ut->ut_host[0])) {
|
||||
hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
|
||||
strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
|
||||
hostname[sizeof (ut->ut_host)] = '\0';
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
}
|
||||
|
||||
if (strncmp(line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update utmpx. We create an empty entry in case there is
|
||||
* no matching entry in the utmpx file.
|
||||
|
||||
utent = (struct utmp *) xmalloc (sizeof (*utent));
|
||||
memzero (utent, sizeof (*utent));
|
||||
|
||||
|
||||
|
||||
#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, sizeof (utent->ut_line));
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ID
|
||||
strncpy (utent->ut_id, ut->ut_id, sizeof (utent->ut_id));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ID */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_NAME
|
||||
strncpy (utent->ut_name, name, sizeof (utent->ut_name));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_NAME */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_USER
|
||||
strncpy (utent->ut_user, name, sizeof (utent->ut_user));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_USER */
|
||||
if (NULL != hostname) {
|
||||
struct addrinfo *info = NULL;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
strncpy (utent->ut_host, hostname, sizeof (utent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
|
||||
utent->ut_syslen = MIN (strlen (hostname),
|
||||
sizeof (utent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_SYSLEN */
|
||||
#if defined(HAVE_STRUCT_UTMP_UT_ADDR) || defined(HAVE_STRUCT_UTMP_UT_ADDR_V6)
|
||||
if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
|
||||
/* getaddrinfo might not be reliable.
|
||||
* Just try to log what may be useful.
|
||||
*/
|
||||
|
||||
setutxent ();
|
||||
setutent ();
|
||||
|
||||
while ((utmpx = getutxent ()) != NULL) {
|
||||
if (utmpx->ut_pid == pid) {
|
||||
found_utmpx = true;
|
||||
break;
|
||||
if (info->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sa =
|
||||
(struct sockaddr_in *) info->ai_addr;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ADDR
|
||||
memcpy (&(utent->ut_addr),
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utent->ut_addr),
|
||||
sizeof (sa->sin_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ADDR_V6
|
||||
memcpy (utent->ut_addr_v6,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utent->ut_addr_v6),
|
||||
sizeof (sa->sin_addr)));
|
||||
} else if (info->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa =
|
||||
(struct sockaddr_in6 *) info->ai_addr;
|
||||
memcpy (utent->ut_addr_v6,
|
||||
&(sa->sin6_addr),
|
||||
MIN (sizeof (utent->ut_addr_v6),
|
||||
sizeof (sa->sin6_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR_V6 */
|
||||
}
|
||||
freeaddrinfo (info);
|
||||
}
|
||||
while ((utmp = getutent ()) != NULL) {
|
||||
if (utmp->ut_pid == pid) {
|
||||
found_utmp = true;
|
||||
break;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR || HAVE_STRUCT_UTMP_UT_ADDR_V6 */
|
||||
free (hostname);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the entry matching `pid' cannot be found, create a new
|
||||
* entry with the device name in it.
|
||||
*/
|
||||
|
||||
if (!found_utmpx) {
|
||||
memset ((void *) &utxline, 0, sizeof utxline);
|
||||
strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
|
||||
utxline.ut_pid = getpid ();
|
||||
} else {
|
||||
utxline = *utmpx;
|
||||
if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
|
||||
memmove (utxline.ut_line, utxline.ut_line + 5,
|
||||
sizeof utxline.ut_line - 5);
|
||||
utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
|
||||
}
|
||||
}
|
||||
if (!found_utmp) {
|
||||
memset ((void *) &utline, 0, sizeof utline);
|
||||
strncpy (utline.ut_line, utxline.ut_line,
|
||||
sizeof utline.ut_line);
|
||||
utline.ut_pid = utxline.ut_pid;
|
||||
} else {
|
||||
utline = *utmp;
|
||||
if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
|
||||
memmove (utline.ut_line, utline.ut_line + 5,
|
||||
sizeof utline.ut_line - 5);
|
||||
utline.ut_line[sizeof utline.ut_line - 5] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the fields in the utmpx entry and write it out. Do
|
||||
* the utmp entry at the same time to make sure things don't
|
||||
* get messed up.
|
||||
*/
|
||||
|
||||
strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
|
||||
strncpy (utline.ut_user, name, sizeof utline.ut_user);
|
||||
|
||||
utline.ut_type = utxline.ut_type = USER_PROCESS;
|
||||
|
||||
if (sizeof (utxline.ut_tv) == sizeof (struct timeval)) {
|
||||
gettimeofday ((struct timeval *) &utxline.ut_tv, NULL);
|
||||
} else {
|
||||
struct timeval tv;
|
||||
|
||||
/* ut_exit is only for DEAD_PROCESS */
|
||||
utent->ut_session = getsid (0);
|
||||
gettimeofday (&tv, NULL);
|
||||
utxline.ut_tv.tv_sec = tv.tv_sec;
|
||||
utxline.ut_tv.tv_usec = tv.tv_usec;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_TIME
|
||||
utent->ut_time = tv.tv_sec;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TIME */
|
||||
#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;
|
||||
}
|
||||
utline.ut_time = utxline.ut_tv.tv_sec;
|
||||
|
||||
strncpy (utxline.ut_host, (NULL != host) ? host : "",
|
||||
sizeof utxline.ut_host);
|
||||
/*
|
||||
* setutmp - Update an entry in utmp and log an entry in wtmp
|
||||
*
|
||||
* Return 1 on failure and 0 on success.
|
||||
*/
|
||||
int setutmp (struct utmp *ut)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if ( (pututxline (&utxline) == NULL)
|
||||
|| (pututline (&utline) == NULL)) {
|
||||
assert (NULL != ut);
|
||||
|
||||
setutent ();
|
||||
if (pututline (ut) == NULL) {
|
||||
err = 1;
|
||||
}
|
||||
|
||||
updwtmpx (_WTMP_FILE "x", &utxline);
|
||||
updwtmp (_WTMP_FILE, &utline);
|
||||
|
||||
utxent = utxline;
|
||||
utent = utline;
|
||||
|
||||
endutxent ();
|
||||
endutent ();
|
||||
|
||||
updwtmp (_WTMP_FILE, ut);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_UTMPX_H
|
||||
/*
|
||||
* prepare_utmpx - the UTMPX version for prepare_utmp
|
||||
*/
|
||||
struct utmpx *prepare_utmpx (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
struct utmp *ut)
|
||||
{
|
||||
struct timeval tv;
|
||||
char *hostname = NULL;
|
||||
struct utmpx *utxent;
|
||||
|
||||
assert (NULL != name);
|
||||
assert (NULL != line);
|
||||
assert (NULL != ut);
|
||||
|
||||
|
||||
|
||||
if ( (NULL != host)
|
||||
&& ('\0' != host)) {
|
||||
hostname = (char *) xmalloc (strlen (host) + 1);
|
||||
strcpy (hostname, host);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
} else if ( (NULL != ut->ut_host)
|
||||
&& ('\0' != ut->ut_host[0])) {
|
||||
hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
|
||||
strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
|
||||
hostname[sizeof (ut->ut_host)] = '\0';
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
|
||||
}
|
||||
|
||||
if (strncmp(line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
utxent = (struct utmpx *) xmalloc (sizeof (*utxent));
|
||||
memzero (utxent, sizeof (*utxent));
|
||||
|
||||
|
||||
|
||||
utxent->ut_type = USER_PROCESS;
|
||||
utxent->ut_pid = getpid ();
|
||||
strncpy (utxent->ut_line, line, sizeof (utxent->ut_line));
|
||||
#ifndef HAVE_STRUCT_UTMP_UT_ID
|
||||
// FIXME: move to configure.in
|
||||
# error "No support for systems with utmpx and no ut_id field in utmp"
|
||||
#endif /* !HAVE_STRUCT_UTMP_UT_ID */
|
||||
strncpy (utxent->ut_id, ut->ut_id, sizeof (utxent->ut_id));
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_NAME
|
||||
strncpy (utxent->ut_name, name, sizeof (utxent->ut_name));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_NAME */
|
||||
strncpy (utxent->ut_user, name, sizeof (utxent->ut_user));
|
||||
if (NULL != hostname) {
|
||||
struct addrinfo *info = NULL;
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_HOST
|
||||
strncpy (utxent->ut_host, hostname, sizeof (utxent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_HOST */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
|
||||
utxent->ut_syslen = MIN (strlen (hostname),
|
||||
sizeof (utxent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_SYSLEN */
|
||||
#if defined(HAVE_STRUCT_UTMPX_UT_ADDR) || defined(HAVE_STRUCT_UTMPX_UT_ADDR_V6)
|
||||
if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
|
||||
/* getaddrinfo might not be reliable.
|
||||
* Just try to log what may be useful.
|
||||
*/
|
||||
if (info->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sa =
|
||||
(struct sockaddr_in *) info->ai_addr;
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_ADDR
|
||||
memcpy (utxent->ut_addr,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utxent->ut_addr),
|
||||
sizeof (sa->sin_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_ADDR_V6
|
||||
memcpy (utxent->ut_addr_v6,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utxent->ut_addr_v6),
|
||||
sizeof (sa->sin_addr)));
|
||||
} else if (info->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa =
|
||||
(struct sockaddr_in6 *) info->ai_addr;
|
||||
memcpy (utxent->ut_addr_v6,
|
||||
&(sa->sin6_addr),
|
||||
MIN (sizeof (utxent->ut_addr_v6),
|
||||
sizeof (sa->sin6_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
|
||||
}
|
||||
freeaddrinfo (info);
|
||||
}
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR || HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
|
||||
free (hostname);
|
||||
}
|
||||
/* ut_exit is only for DEAD_PROCESS */
|
||||
utxent->ut_session = getsid (0);
|
||||
gettimeofday (&tv, NULL);
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_TIME
|
||||
utxent->ut_time = tv.tv_sec;
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_TIME */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_XTIME
|
||||
utxent->ut_xtime = tv.tv_usec;
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_XTIME */
|
||||
utxent->ut_tv.tv_sec = tv.tv_sec;
|
||||
utxent->ut_tv.tv_usec = tv.tv_usec;
|
||||
|
||||
return utxent;
|
||||
}
|
||||
|
||||
/*
|
||||
* setutmpx - the UTMPX version for setutmp
|
||||
*/
|
||||
int setutmpx (struct utmpx *utx)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
assert (NULL != utx);
|
||||
|
||||
setutxent ();
|
||||
if (pututxline (utx) == NULL) {
|
||||
err = 1;
|
||||
}
|
||||
endutxent ();
|
||||
|
||||
updwtmpx (_WTMP_FILE "x", utx);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* HAVE_UTMPX_H */
|
||||
|
||||
|
115
src/login.c
115
src/login.c
@ -85,14 +85,6 @@ static const char *hostname = "";
|
||||
static char *username = NULL;
|
||||
static int reason = PW_LOGIN;
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
extern struct utmpx utxent;
|
||||
struct utmpx failent;
|
||||
#else
|
||||
struct utmp failent;
|
||||
#endif
|
||||
extern struct utmp utent;
|
||||
|
||||
struct lastlog lastlog;
|
||||
static bool pflg = false;
|
||||
static bool fflg = false;
|
||||
@ -128,7 +120,7 @@ extern char **environ;
|
||||
static void usage (void);
|
||||
static void setup_tty (void);
|
||||
static void process_flags (int, char *const *);
|
||||
static const char *get_failent_user (const char *user)
|
||||
static const char *get_failent_user (const char *user);
|
||||
|
||||
#ifndef USE_PAM
|
||||
static struct faillog faillog;
|
||||
@ -494,6 +486,7 @@ int main (int argc, char **argv)
|
||||
static char temp_shell[] = "/bin/sh";
|
||||
#endif
|
||||
const char *failent_user;
|
||||
struct utmp *utent;
|
||||
|
||||
#ifdef USE_PAM
|
||||
int retcode;
|
||||
@ -523,6 +516,7 @@ int main (int argc, char **argv)
|
||||
exit (1); /* must be a terminal */
|
||||
}
|
||||
|
||||
utent = get_current_utmp ();
|
||||
/*
|
||||
* Be picky if run by normal users (possible if installed setuid
|
||||
* root), but not if run by root. This way it still allows logins
|
||||
@ -530,7 +524,10 @@ int main (int argc, char **argv)
|
||||
* but users must "exec login" which will use the existing utmp
|
||||
* entry (will not overwrite remote hostname). --marekm
|
||||
*/
|
||||
checkutmp (!amroot);
|
||||
if (!amroot && (NULL == utent)) {
|
||||
(void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
tmptty = ttyname (0);
|
||||
if (NULL == tmptty) {
|
||||
@ -543,44 +540,12 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
if (rflg || hflg) {
|
||||
#ifdef UT_ADDR
|
||||
struct hostent *he;
|
||||
|
||||
/*
|
||||
* Fill in the ut_addr field (remote login IP address). XXX
|
||||
* - login from util-linux does it, but this is not the
|
||||
* right place to do it. The program that starts login
|
||||
* (telnetd, rlogind) knows the IP address, so it should
|
||||
* create the utmp entry and fill in ut_addr.
|
||||
* gethostbyname() is not 100% reliable (the remote host may
|
||||
* be unknown, etc.). --marekm
|
||||
*/
|
||||
he = gethostbyname (hostname);
|
||||
if (NULL != he) {
|
||||
utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
|
||||
}
|
||||
#endif
|
||||
#ifdef UT_HOST
|
||||
strncpy (utent.ut_host, hostname, sizeof (utent.ut_host));
|
||||
#endif
|
||||
#if HAVE_UTMPX_H
|
||||
strncpy (utxent.ut_host, hostname, sizeof (utxent.ut_host));
|
||||
#endif
|
||||
/*
|
||||
* Add remote hostname to the environment. I think
|
||||
* (not sure) I saw it once on Irix. --marekm
|
||||
*/
|
||||
addenv ("REMOTEHOST", hostname);
|
||||
}
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* workaround for init/getty leaving junk in ut_host at least in
|
||||
* some version of RedHat. --marekm
|
||||
*/
|
||||
else if (amroot) {
|
||||
memzero (utent.ut_host, sizeof utent.ut_host);
|
||||
}
|
||||
#endif
|
||||
if (fflg) {
|
||||
preauth_flag = true;
|
||||
}
|
||||
@ -656,18 +621,11 @@ int main (int argc, char **argv)
|
||||
if (rflg || hflg) {
|
||||
cp = hostname;
|
||||
} else {
|
||||
/* FIXME: What is the priority:
|
||||
* UT_HOST or HAVE_UTMPX_H? */
|
||||
#ifdef UT_HOST
|
||||
if ('\0' != utent.ut_host[0]) {
|
||||
cp = utent.ut_host;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
if ('\0' != utent->ut_host[0]) {
|
||||
cp = utent->ut_host;
|
||||
} else
|
||||
#endif
|
||||
#if HAVE_UTMPX_H
|
||||
if ('\0' != utxent.ut_host[0]) {
|
||||
cp = utxent.ut_host;
|
||||
} else
|
||||
#endif
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
{
|
||||
cp = "";
|
||||
}
|
||||
@ -888,17 +846,17 @@ int main (int argc, char **argv)
|
||||
while (true) { /* repeatedly get login/password pairs */
|
||||
/* user_passwd is always a pointer to this constant string
|
||||
* or a passwd or shadow password that will be memzero by
|
||||
* passwd_free / shadow_free.
|
||||
* pw_free / spw_free.
|
||||
* Do not free() user_passwd. */
|
||||
const char *user_passwd = "!";
|
||||
|
||||
/* Do some cleanup to avoid keeping entries we do not need
|
||||
* anymore. */
|
||||
if (NULL != pwd) {
|
||||
passwd_free (pwd);
|
||||
pw_free (pwd);
|
||||
}
|
||||
if (NULL != spwd) {
|
||||
shadow_free (spwd);
|
||||
spw_free (spwd);
|
||||
spwd = NULL;
|
||||
}
|
||||
|
||||
@ -1007,26 +965,21 @@ int main (int argc, char **argv)
|
||||
failure (pwd->pw_uid, tty, &faillog);
|
||||
}
|
||||
if (getdef_str ("FTMP_FILE") != NULL) {
|
||||
#if HAVE_UTMPX_H
|
||||
failent = utxent;
|
||||
if (sizeof (failent.ut_tv) == sizeof (struct timeval)) {
|
||||
gettimeofday ((struct timeval *) &failent.ut_tv,
|
||||
NULL);
|
||||
} else {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
failent.ut_tv.tv_sec = tv.tv_sec;
|
||||
failent.ut_tv.tv_usec = tv.tv_usec;
|
||||
}
|
||||
#ifdef HAVE_UTMPX_H
|
||||
struct utmpx *failent =
|
||||
prepare_utmpx (failent_user,
|
||||
tty,
|
||||
/* FIXME: or fromhost? */hostname,
|
||||
utent);
|
||||
#else
|
||||
failent = utent;
|
||||
failent.ut_time = time (NULL);
|
||||
struct utmp *failent =
|
||||
prepare_utmp (failent_user,
|
||||
tty,
|
||||
hostname,
|
||||
utent);
|
||||
#endif
|
||||
strncpy (failent.ut_user, failent_user,
|
||||
sizeof (failent.ut_user));
|
||||
failent.ut_type = USER_PROCESS;
|
||||
failtmp (failent_user, &failent);
|
||||
failtmp (failent_user, failent);
|
||||
free (failent);
|
||||
}
|
||||
|
||||
retries--;
|
||||
@ -1096,7 +1049,15 @@ int main (int argc, char **argv)
|
||||
addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
|
||||
}
|
||||
|
||||
setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
|
||||
struct utmp *ut = prepare_utmp (username, tty, hostname, utent);
|
||||
(void) setutmp (ut); /* make entry in the utmp & wtmp files */
|
||||
free (ut);
|
||||
#ifdef HAVE_UTMPX_H
|
||||
struct utmpx *utx = prepare_utmpx (username, tty, hostname, utent);
|
||||
(void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
|
||||
free (utx);
|
||||
#endif /* HAVE_UTMPX_H */
|
||||
|
||||
if (pwd->pw_shell[0] == '*') { /* subsystem root */
|
||||
pwd->pw_shell++; /* skip the '*' */
|
||||
subsystem (pwd); /* figure out what to execute */
|
||||
@ -1144,7 +1105,7 @@ int main (int argc, char **argv)
|
||||
* entry for a long time, and there might be other
|
||||
* getxxyy in between.
|
||||
*/
|
||||
passwd_free (pwd);
|
||||
pw_free (pwd);
|
||||
pwd = xgetpwnam (username);
|
||||
if (NULL == pwd) {
|
||||
SYSLOG ((LOG_ERR,
|
||||
@ -1152,7 +1113,7 @@ int main (int argc, char **argv)
|
||||
username));
|
||||
exit (1);
|
||||
}
|
||||
shadow_free (spwd);
|
||||
spw_free (spwd);
|
||||
spwd = xgetspnam (username);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user