[Pkg-shadow-commits] r2737 - in upstream/trunk: . lib libmisc src

Nicolas FRANÇOIS nekral-guest at alioth.debian.org
Tue Apr 21 22:39:14 UTC 2009


Author: nekral-guest
Date: 2009-04-21 22:39:14 +0000 (Tue, 21 Apr 2009)
New Revision: 2737

Modified:
   upstream/trunk/configure.in
   upstream/trunk/lib/prototypes.h
   upstream/trunk/libmisc/utmp.c
   upstream/trunk/src/login.c
Log:
	* 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()


Modified: upstream/trunk/configure.in
===================================================================
--- upstream/trunk/configure.in	2009-04-21 22:22:08 UTC (rev 2736)
+++ upstream/trunk/configure.in	2009-04-21 22:39:14 UTC (rev 2737)
@@ -41,7 +41,7 @@
 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_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,

Modified: upstream/trunk/lib/prototypes.h
===================================================================
--- upstream/trunk/lib/prototypes.h	2009-04-21 22:22:08 UTC (rev 2736)
+++ upstream/trunk/lib/prototypes.h	2009-04-21 22:39:14 UTC (rev 2737)
@@ -345,8 +345,19 @@
 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 *);

Modified: upstream/trunk/libmisc/utmp.c
===================================================================
--- upstream/trunk/libmisc/utmp.c	2009-04-21 22:22:08 UTC (rev 2736)
+++ upstream/trunk/libmisc/utmp.c	2009-04-21 22:39:14 UTC (rev 2737)
@@ -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,44 +37,41 @@
 
 #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
  */
 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 @@
 }
 
 /*
- * 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 @@
 		}
 	}
 
-	/* 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 @@
  * 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;
-	}
-	endutent ();
-	updwtmp (_WTMP_FILE, &utent);
+	struct timeval tv;
+	char *hostname = NULL;
+	struct utmp *utent;
 
-	return err;
-}
+	assert (NULL != name);
+	assert (NULL != line);
+	assert (NULL != ut);
 
-#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.
-	 */
+	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) {
+	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.
-	 */
 
-	setutxent ();
-	setutent ();
+	utent = (struct utmp *) xmalloc (sizeof (*utent));
+	memzero (utent, sizeof (*utent));
 
-	while ((utmpx = getutxent ()) != NULL) {
-		if (utmpx->ut_pid == pid) {
-			found_utmpx = true;
-			break;
+
+
+#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);
 	}
-	while ((utmp = getutent ()) != NULL) {
-		if (utmp->ut_pid == pid) {
-			found_utmp = true;
-			break;
-		}
-	}
+	/* 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 */
 
-	/*
-	 * If the entry matching `pid' cannot be found, create a new
-	 * entry with the device name in it.
-	 */
+	return utent;
+}
 
-	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';
-		}
+/*
+ * 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;
+
+	assert (NULL != ut);
+
+	setutent ();
+	if (pututline (ut) == NULL) {
+		err = 1;
 	}
-	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';
-		}
-	}
+	endutent ();
 
-	/*
-	 * 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.
-	 */
+	updwtmp (_WTMP_FILE, ut);
 
-	strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
-	strncpy (utline.ut_user, name, sizeof utline.ut_user);
+	return err;
+}
 
-	utline.ut_type = utxline.ut_type = USER_PROCESS;
+#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;
 
-	if (sizeof (utxline.ut_tv) == sizeof (struct timeval)) {
-		gettimeofday ((struct timeval *) &utxline.ut_tv, NULL);
-	} else {
-		struct timeval tv;
+	assert (NULL != name);
+	assert (NULL != line);
+	assert (NULL != ut);
 
-		gettimeofday (&tv, NULL);
-		utxline.ut_tv.tv_sec = tv.tv_sec;
-		utxline.ut_tv.tv_usec = tv.tv_usec;
+
+
+	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 */
 	}
-	utline.ut_time = utxline.ut_tv.tv_sec;
 
-	strncpy (utxline.ut_host, (NULL != host) ? host : "",
-	         sizeof utxline.ut_host);
+	if (strncmp(line, "/dev/", 5) == 0) {
+		line += 5;
+	}
 
-	if (   (pututxline (&utxline) == NULL)
-	    || (pututline (&utline) == NULL)) {
-		err = 1;
+	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;
 
-	updwtmpx (_WTMP_FILE "x", &utxline);
-	updwtmp (_WTMP_FILE, &utline);
+	return utxent;
+}
 
-	utxent = utxline;
-	utent = utline;
+/*
+ * 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 ();
-	endutent ();
 
+	updwtmpx (_WTMP_FILE "x", utx);
+
 	return err;
 }
+#endif				/* HAVE_UTMPX_H */
 
-#endif

Modified: upstream/trunk/src/login.c
===================================================================
--- upstream/trunk/src/login.c	2009-04-21 22:22:08 UTC (rev 2736)
+++ upstream/trunk/src/login.c	2009-04-21 22:39:14 UTC (rev 2737)
@@ -85,14 +85,6 @@
 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 @@
 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 @@
 	static char temp_shell[] = "/bin/sh";
 #endif
 	const char *failent_user;
+	struct utmp *utent;
 
 #ifdef USE_PAM
 	int retcode;
@@ -523,6 +516,7 @@
 		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 @@
 	 * 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 @@
 #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 @@
 	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 @@
 	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 @@
 			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 @@
 		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 @@
 			 * 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 @@
 				         username));
 				exit (1);
 			}
-			shadow_free (spwd);
+			spw_free (spwd);
 			spwd = xgetspnam (username);
 		}
 	}




More information about the Pkg-shadow-commits mailing list