]> granicus.if.org Git - shadow/commitdiff
* libmisc/utmp.c: Reworked. Get rid of Linux specific stuff. Get rid
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Tue, 21 Apr 2009 22:39:14 +0000 (22:39 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Tue, 21 Apr 2009 22:39:14 +0000 (22:39 +0000)
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()

configure.in
lib/prototypes.h
libmisc/utmp.c
src/login.c

index 073eb27c947813f6df86d639a6bce2a75965825c..46d37f90e8dfc5800c5448890bda2e7ea69e9c8c 100644 (file)
@@ -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,38 +59,32 @@ 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.])
-       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
+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_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,
                ac_cv_struct_lastlog_ll_host,
index 56ab225c4f1ee167fe087cfe0ad0f482913c8c30..bc2dabd9a96fda8f81e625625154eaa8ce0d4c54 100644 (file)
@@ -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 *);
index 0c7a5d143251fa9ba8982bf4565d5e2e5c66a096..32843a1cb82abb8960c4f213d2bbbf9584d6168f 100644 (file)
@@ -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
 
 #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);
-               }
-               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);
+               ret = malloc (sizeof (*ret));
+               memcpy (ret, ut, sizeof (*ret));
        }
 
-       /* 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;
-                       }
-               }
 
-               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 ();
+       return ret;
 }
 
-#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))
+/*
+ * 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)
 {
-       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;
+       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 */
        }
-       endutent ();
-       updwtmp (_WTMP_FILE, &utent);
 
-       return err;
-}
+       if (strncmp(line, "/dev/", 5) == 0) {
+               line += 5;
+       }
 
-#elif HAVE_UTMPX_H
 
-int setutmp (const char *name, const char *line, const char *host)
+       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.
+                        */
+                       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);
+               }
+#endif         /* HAVE_STRUCT_UTMP_UT_ADDR || HAVE_STRUCT_UTMP_UT_ADDR_V6 */
+               free (hostname);
+       }
+       /* ut_exit is only for DEAD_PROCESS */
+       utent->ut_session = getsid (0);
+       gettimeofday (&tv, NULL);
+#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;
+}
+
+/*
+ * 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)
 {
-       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.
-        */
+       assert (NULL != ut);
 
-       if (strncmp (line, "/dev/", 5) == 0) {
-               line += 5;
+       setutent ();
+       if (pututline (ut) == NULL) {
+               err = 1;
        }
+       endutent ();
 
-       /*
-        * Update utmpx.  We create an empty entry in case there is
-        * no matching entry in the utmpx file.
-        */
+       updwtmp (_WTMP_FILE, ut);
 
-       setutxent ();
-       setutent ();
+       return err;
+}
 
-       while ((utmpx = getutxent ()) != NULL) {
-               if (utmpx->ut_pid == pid) {
-                       found_utmpx = true;
-                       break;
-               }
-       }
-       while ((utmp = getutent ()) != NULL) {
-               if (utmp->ut_pid == pid) {
-                       found_utmp = true;
-                       break;
-               }
+#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 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 (strncmp(line, "/dev/", 5) == 0) {
+               line += 5;
        }
-       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';
+
+       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;
+}
 
-       /*
-        * 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;
-
-               gettimeofday (&tv, NULL);
-               utxline.ut_tv.tv_sec = tv.tv_sec;
-               utxline.ut_tv.tv_usec = tv.tv_usec;
-       }
-       utline.ut_time = utxline.ut_tv.tv_sec;
+/*
+ * setutmpx - the UTMPX version for setutmp
+ */
+int setutmpx (struct utmpx *utx)
+{
+       int err = 0;
 
-       strncpy (utxline.ut_host, (NULL != host) ? host : "",
-                sizeof utxline.ut_host);
+       assert (NULL != utx);
 
-       if (   (pututxline (&utxline) == NULL)
-           || (pututline (&utline) == NULL)) {
+       setutxent ();
+       if (pututxline (utx) == NULL) {
                err = 1;
        }
-
-       updwtmpx (_WTMP_FILE "x", &utxline);
-       updwtmp (_WTMP_FILE, &utline);
-
-       utxent = utxline;
-       utent = utline;
-
        endutxent ();
-       endutent ();
+
+       updwtmpx (_WTMP_FILE "x", utx);
 
        return err;
 }
+#endif                         /* HAVE_UTMPX_H */
 
-#endif
index 2f4f29a6b6a82c00c80c5cf189efaabaeb801dbf..1e0a39eddc8e4a64a08fcf92eb54cd38952cfdd3 100644 (file)
@@ -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;
-               } else
-#endif
-#if HAVE_UTMPX_H
-               if ('\0' != utxent.ut_host[0]) {
-                       cp = utxent.ut_host;
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+               if ('\0' != utent->ut_host[0]) {
+                       cp = utent->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);
                }
        }