xref: /titanic_50/usr/src/cmd/ssh/sshd/loginrec.c (revision 2de0a7d66c00b4cb047dc93352fe8b77707d2838)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Andre Lucas.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1998 Todd C. Miller
47c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1996 Jason Downs
57c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1996 Theo de Raadt
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
87c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
97c478bd9Sstevel@tonic-gate  * are met:
107c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
117c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
127c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
137c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
147c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
157c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
167c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
177c478bd9Sstevel@tonic-gate  *      This product includes software developed by Markus Friedl.
187c478bd9Sstevel@tonic-gate  * 4. The name of the author may not be used to endorse or promote products
197c478bd9Sstevel@tonic-gate  *    derived from this software without specific prior written permission.
207c478bd9Sstevel@tonic-gate  *
217c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
227c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
237c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
247c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
257c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
267c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
277c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
287c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
297c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
307c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
317c478bd9Sstevel@tonic-gate  */
32b9aa66a7SJan Pechanec /*
33b9aa66a7SJan Pechanec  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
34b9aa66a7SJan Pechanec  * Use is subject to license terms.
35b9aa66a7SJan Pechanec  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /**
387c478bd9Sstevel@tonic-gate  ** loginrec.c:  platform-independent login recording and lastlog retrieval
397c478bd9Sstevel@tonic-gate  **/
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate   The new login code explained
437c478bd9Sstevel@tonic-gate   ============================
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate   This code attempts to provide a common interface to login recording
467c478bd9Sstevel@tonic-gate   (utmp and friends) and last login time retrieval.
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate   Its primary means of achieving this is to use 'struct logininfo', a
497c478bd9Sstevel@tonic-gate   union of all the useful fields in the various different types of
507c478bd9Sstevel@tonic-gate   system login record structures one finds on UNIX variants.
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate   We depend on autoconf to define which recording methods are to be
537c478bd9Sstevel@tonic-gate   used, and which fields are contained in the relevant data structures
547c478bd9Sstevel@tonic-gate   on the local system. Many C preprocessor symbols affect which code
557c478bd9Sstevel@tonic-gate   gets compiled here.
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate   The code is designed to make it easy to modify a particular
587c478bd9Sstevel@tonic-gate   recording method, without affecting other methods nor requiring so
597c478bd9Sstevel@tonic-gate   many nested conditional compilation blocks as were commonplace in
607c478bd9Sstevel@tonic-gate   the old code.
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate   For login recording, we try to use the local system's libraries as
637c478bd9Sstevel@tonic-gate   these are clearly most likely to work correctly. For utmp systems
647c478bd9Sstevel@tonic-gate   this usually means login() and logout() or setutent() etc., probably
657c478bd9Sstevel@tonic-gate   in libutil, along with logwtmp() etc. On these systems, we fall back
667c478bd9Sstevel@tonic-gate   to writing the files directly if we have to, though this method
677c478bd9Sstevel@tonic-gate   requires very thorough testing so we do not corrupt local auditing
687c478bd9Sstevel@tonic-gate   information. These files and their access methods are very system
697c478bd9Sstevel@tonic-gate   specific indeed.
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate   For utmpx systems, the corresponding library functions are
727c478bd9Sstevel@tonic-gate   setutxent() etc. To the author's knowledge, all utmpx systems have
737c478bd9Sstevel@tonic-gate   these library functions and so no direct write is attempted. If such
747c478bd9Sstevel@tonic-gate   a system exists and needs support, direct analogues of the [uw]tmp
757c478bd9Sstevel@tonic-gate   code should suffice.
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate   Retrieving the time of last login ('lastlog') is in some ways even
787c478bd9Sstevel@tonic-gate   more problemmatic than login recording. Some systems provide a
797c478bd9Sstevel@tonic-gate   simple table of all users which we seek based on uid and retrieve a
807c478bd9Sstevel@tonic-gate   relatively standard structure. Others record the same information in
817c478bd9Sstevel@tonic-gate   a directory with a separate file, and others don't record the
827c478bd9Sstevel@tonic-gate   information separately at all. For systems in the latter category,
837c478bd9Sstevel@tonic-gate   we look backwards in the wtmp or wtmpx file for the last login entry
847c478bd9Sstevel@tonic-gate   for our user. Naturally this is slower and on busy systems could
857c478bd9Sstevel@tonic-gate   incur a significant performance penalty.
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate   Calling the new code
887c478bd9Sstevel@tonic-gate   --------------------
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate   In OpenSSH all login recording and retrieval is performed in
917c478bd9Sstevel@tonic-gate   login.c. Here you'll find working examples. Also, in the logintest.c
927c478bd9Sstevel@tonic-gate   program there are more examples.
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate   Internal handler calling method
957c478bd9Sstevel@tonic-gate   -------------------------------
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate   When a call is made to login_login() or login_logout(), both
987c478bd9Sstevel@tonic-gate   routines set a struct logininfo flag defining which action (log in,
997c478bd9Sstevel@tonic-gate   or log out) is to be taken. They both then call login_write(), which
1007c478bd9Sstevel@tonic-gate   calls whichever of the many structure-specific handlers autoconf
1017c478bd9Sstevel@tonic-gate   selects for the local system.
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate   The handlers themselves handle system data structure specifics. Both
1047c478bd9Sstevel@tonic-gate   struct utmp and struct utmpx have utility functions (see
1057c478bd9Sstevel@tonic-gate   construct_utmp*()) to try to make it simpler to add extra systems
1067c478bd9Sstevel@tonic-gate   that introduce new features to either structure.
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate   While it may seem terribly wasteful to replicate so much similar
1097c478bd9Sstevel@tonic-gate   code for each method, experience has shown that maintaining code to
1107c478bd9Sstevel@tonic-gate   write both struct utmp and utmpx in one function, whilst maintaining
1117c478bd9Sstevel@tonic-gate   support for all systems whether they have library support or not, is
1127c478bd9Sstevel@tonic-gate   a difficult and time-consuming task.
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate   Lastlog support proceeds similarly. Functions login_get_lastlog()
1157c478bd9Sstevel@tonic-gate   (and its OpenSSH-tuned friend login_get_lastlog_time()) call
1167c478bd9Sstevel@tonic-gate   getlast_entry(), which tries one of three methods to find the last
1177c478bd9Sstevel@tonic-gate   login time. It uses local system lastlog support if it can,
1187c478bd9Sstevel@tonic-gate   otherwise it tries wtmp or wtmpx before giving up and returning 0,
1197c478bd9Sstevel@tonic-gate   meaning "tilt".
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate   Maintenance
1227c478bd9Sstevel@tonic-gate   -----------
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate   In many cases it's possible to tweak autoconf to select the correct
1257c478bd9Sstevel@tonic-gate   methods for a particular platform, either by improving the detection
1267c478bd9Sstevel@tonic-gate   code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
1277c478bd9Sstevel@tonic-gate   symbols for the platform.
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate   Use logintest to check which symbols are defined before modifying
1307c478bd9Sstevel@tonic-gate   configure.ac and loginrec.c. (You have to build logintest yourself
1317c478bd9Sstevel@tonic-gate   with 'make logintest' as it's not built by default.)
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate   Otherwise, patches to the specific method(s) are very helpful!
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /**
1387c478bd9Sstevel@tonic-gate  ** TODO:
1397c478bd9Sstevel@tonic-gate  **   homegrown ttyslot()
1407c478bd9Sstevel@tonic-gate  **   test, test, test
1417c478bd9Sstevel@tonic-gate  **
1427c478bd9Sstevel@tonic-gate  ** Platform status:
1437c478bd9Sstevel@tonic-gate  ** ----------------
1447c478bd9Sstevel@tonic-gate  **
1457c478bd9Sstevel@tonic-gate  ** Known good:
1467c478bd9Sstevel@tonic-gate  **   Linux (Redhat 6.2, Debian)
1477c478bd9Sstevel@tonic-gate  **   Solaris
1487c478bd9Sstevel@tonic-gate  **   HP-UX 10.20 (gcc only)
1497c478bd9Sstevel@tonic-gate  **   IRIX
1507c478bd9Sstevel@tonic-gate  **   NeXT - M68k/HPPA/Sparc (4.2/3.3)
1517c478bd9Sstevel@tonic-gate  **
1527c478bd9Sstevel@tonic-gate  ** Testing required: Please send reports!
1537c478bd9Sstevel@tonic-gate  **   NetBSD
1547c478bd9Sstevel@tonic-gate  **   HP-UX 11
1557c478bd9Sstevel@tonic-gate  **   AIX
1567c478bd9Sstevel@tonic-gate  **
1577c478bd9Sstevel@tonic-gate  ** Platforms with known problems:
1587c478bd9Sstevel@tonic-gate  **   Some variants of Slackware Linux
1597c478bd9Sstevel@tonic-gate  **
1607c478bd9Sstevel@tonic-gate  **/
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate #include "includes.h"
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate #include "ssh.h"
1657c478bd9Sstevel@tonic-gate #include "xmalloc.h"
1667c478bd9Sstevel@tonic-gate #include "loginrec.h"
1677c478bd9Sstevel@tonic-gate #include "log.h"
1687c478bd9Sstevel@tonic-gate #include "atomicio.h"
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate RCSID("$Id: loginrec.c,v 1.44 2002/09/26 00:38:49 tim Exp $");
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate #ifdef HAVE_UTIL_H
1737c478bd9Sstevel@tonic-gate #  include <util.h>
1747c478bd9Sstevel@tonic-gate #endif
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate #ifdef HAVE_LIBUTIL_H
1777c478bd9Sstevel@tonic-gate #   include <libutil.h>
1787c478bd9Sstevel@tonic-gate #endif
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /**
1817c478bd9Sstevel@tonic-gate  ** prototypes for helper functions in this file
1827c478bd9Sstevel@tonic-gate  **/
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate #if HAVE_UTMP_H
1857c478bd9Sstevel@tonic-gate void set_utmp_time(struct logininfo *li, struct utmp *ut);
1867c478bd9Sstevel@tonic-gate void construct_utmp(struct logininfo *li, struct utmp *ut);
1877c478bd9Sstevel@tonic-gate #endif
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate #ifdef HAVE_UTMPX_H
1907c478bd9Sstevel@tonic-gate void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
1917c478bd9Sstevel@tonic-gate void construct_utmpx(struct logininfo *li, struct utmpx *ut);
1927c478bd9Sstevel@tonic-gate #endif
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate int utmp_write_entry(struct logininfo *li);
1957c478bd9Sstevel@tonic-gate int utmpx_write_entry(struct logininfo *li);
1967c478bd9Sstevel@tonic-gate int wtmp_write_entry(struct logininfo *li);
1977c478bd9Sstevel@tonic-gate int wtmpx_write_entry(struct logininfo *li);
1987c478bd9Sstevel@tonic-gate int lastlog_write_entry(struct logininfo *li);
1997c478bd9Sstevel@tonic-gate int syslogin_write_entry(struct logininfo *li);
2007c478bd9Sstevel@tonic-gate 
201*2de0a7d6SDan McDonald int getlast_entry(struct logininfo *li);
2027c478bd9Sstevel@tonic-gate int lastlog_get_entry(struct logininfo *li);
2037c478bd9Sstevel@tonic-gate int wtmp_get_entry(struct logininfo *li);
2047c478bd9Sstevel@tonic-gate int wtmpx_get_entry(struct logininfo *li);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /* pick the shortest string */
2077c478bd9Sstevel@tonic-gate #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /**
2107c478bd9Sstevel@tonic-gate  ** platform-independent login functions
2117c478bd9Sstevel@tonic-gate  **/
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /* login_login(struct logininfo *)     -Record a login
2147c478bd9Sstevel@tonic-gate  *
2157c478bd9Sstevel@tonic-gate  * Call with a pointer to a struct logininfo initialised with
2167c478bd9Sstevel@tonic-gate  * login_init_entry() or login_alloc_entry()
2177c478bd9Sstevel@tonic-gate  *
2187c478bd9Sstevel@tonic-gate  * Returns:
2197c478bd9Sstevel@tonic-gate  *  >0 if successful
2207c478bd9Sstevel@tonic-gate  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
2217c478bd9Sstevel@tonic-gate  */
2227c478bd9Sstevel@tonic-gate int
login_login(struct logininfo * li)2237c478bd9Sstevel@tonic-gate login_login (struct logininfo *li)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	li->type = LTYPE_LOGIN;
2267c478bd9Sstevel@tonic-gate 	return login_write(li);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /* login_logout(struct logininfo *)     - Record a logout
2317c478bd9Sstevel@tonic-gate  *
2327c478bd9Sstevel@tonic-gate  * Call as with login_login()
2337c478bd9Sstevel@tonic-gate  *
2347c478bd9Sstevel@tonic-gate  * Returns:
2357c478bd9Sstevel@tonic-gate  *  >0 if successful
2367c478bd9Sstevel@tonic-gate  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate int
login_logout(struct logininfo * li)2397c478bd9Sstevel@tonic-gate login_logout(struct logininfo *li)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	li->type = LTYPE_LOGOUT;
2427c478bd9Sstevel@tonic-gate 	return login_write(li);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /* login_get_lastlog_time(int)           - Retrieve the last login time
2467c478bd9Sstevel@tonic-gate  *
2477c478bd9Sstevel@tonic-gate  * Retrieve the last login time for the given uid. Will try to use the
2487c478bd9Sstevel@tonic-gate  * system lastlog facilities if they are available, but will fall back
2497c478bd9Sstevel@tonic-gate  * to looking in wtmp/wtmpx if necessary
2507c478bd9Sstevel@tonic-gate  *
2517c478bd9Sstevel@tonic-gate  * Returns:
2527c478bd9Sstevel@tonic-gate  *   0 on failure, or if user has never logged in
2537c478bd9Sstevel@tonic-gate  *   Time in seconds from the epoch if successful
2547c478bd9Sstevel@tonic-gate  *
2557c478bd9Sstevel@tonic-gate  * Useful preprocessor symbols:
2567c478bd9Sstevel@tonic-gate  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
2577c478bd9Sstevel@tonic-gate  *                    info
2587c478bd9Sstevel@tonic-gate  *   USE_LASTLOG: If set, indicates the presence of system lastlog
2597c478bd9Sstevel@tonic-gate  *                facilities. If this and DISABLE_LASTLOG are not set,
2607c478bd9Sstevel@tonic-gate  *                try to retrieve lastlog information from wtmp/wtmpx.
2617c478bd9Sstevel@tonic-gate  */
2627c478bd9Sstevel@tonic-gate #if 0
2637c478bd9Sstevel@tonic-gate unsigned int
2647c478bd9Sstevel@tonic-gate login_get_lastlog_time(const int uid)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	struct logininfo li;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (login_get_lastlog(&li, uid))
2697c478bd9Sstevel@tonic-gate 		return li.tv_sec;
2707c478bd9Sstevel@tonic-gate 	else
2717c478bd9Sstevel@tonic-gate 		return 0;
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate #endif
2747c478bd9Sstevel@tonic-gate 
275*2de0a7d6SDan McDonald /* login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
276*2de0a7d6SDan McDonald  *
277*2de0a7d6SDan McDonald  * Retrieve a logininfo structure populated (only partially) with
278*2de0a7d6SDan McDonald  * information from the system lastlog data, or from wtmp/wtmpx if no
279*2de0a7d6SDan McDonald  * system lastlog information exists.
280*2de0a7d6SDan McDonald  *
281*2de0a7d6SDan McDonald  * Note this routine must be given a pre-allocated logininfo.
282*2de0a7d6SDan McDonald  *
283*2de0a7d6SDan McDonald  * Returns:
284*2de0a7d6SDan McDonald  *  >0: A pointer to your struct logininfo if successful
285*2de0a7d6SDan McDonald  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
286*2de0a7d6SDan McDonald  *
287*2de0a7d6SDan McDonald  */
288*2de0a7d6SDan McDonald struct logininfo *
login_get_lastlog(struct logininfo * li,const int uid)289*2de0a7d6SDan McDonald login_get_lastlog(struct logininfo *li, const int uid)
290*2de0a7d6SDan McDonald {
291*2de0a7d6SDan McDonald 	struct passwd *pw;
292*2de0a7d6SDan McDonald 
293*2de0a7d6SDan McDonald 	(void) memset(li, '\0', sizeof(*li));
294*2de0a7d6SDan McDonald 	li->uid = uid;
295*2de0a7d6SDan McDonald 
296*2de0a7d6SDan McDonald 	/*
297*2de0a7d6SDan McDonald 	 * If we don't have a 'real' lastlog, we need the username to
298*2de0a7d6SDan McDonald 	 * reliably search wtmp(x) for the last login (see
299*2de0a7d6SDan McDonald 	 * wtmp_get_entry().)
300*2de0a7d6SDan McDonald 	 */
301*2de0a7d6SDan McDonald 	pw = getpwuid(uid);
302*2de0a7d6SDan McDonald 	if (pw == NULL)
303*2de0a7d6SDan McDonald 		fatal("login_get_lastlog: Cannot find account for uid %i", uid);
304*2de0a7d6SDan McDonald 
305*2de0a7d6SDan McDonald 	/* No MIN_SIZEOF here - we absolutely *must not* truncate the
306*2de0a7d6SDan McDonald 	 * username */
307*2de0a7d6SDan McDonald 	(void) strlcpy(li->username, pw->pw_name, sizeof(li->username));
308*2de0a7d6SDan McDonald 
309*2de0a7d6SDan McDonald 	if (getlast_entry(li))
310*2de0a7d6SDan McDonald 		return li;
311*2de0a7d6SDan McDonald 	else
312*2de0a7d6SDan McDonald 		return NULL;
313*2de0a7d6SDan McDonald }
314*2de0a7d6SDan McDonald 
315*2de0a7d6SDan McDonald 
3167c478bd9Sstevel@tonic-gate /* login_alloc_entry()    - Allocate and initialise a logininfo
3177c478bd9Sstevel@tonic-gate  *                           structure
3187c478bd9Sstevel@tonic-gate  *
3197c478bd9Sstevel@tonic-gate  * This function creates a new struct logininfo, a data structure
3207c478bd9Sstevel@tonic-gate  * meant to carry the information required to portably record login info.
3217c478bd9Sstevel@tonic-gate  *
3227c478bd9Sstevel@tonic-gate  * Returns a pointer to a newly created struct logininfo. If memory
3237c478bd9Sstevel@tonic-gate  * allocation fails, the program halts.
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate struct
login_alloc_entry(int pid,const char * username,const char * hostname,const char * line,const char * progname)3267c478bd9Sstevel@tonic-gate logininfo *login_alloc_entry(int pid, const char *username,
3277c478bd9Sstevel@tonic-gate 			     const char *hostname, const char *line,
3287c478bd9Sstevel@tonic-gate 			     const char *progname)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	struct logininfo *newli;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	newli = (struct logininfo *) xmalloc (sizeof(*newli));
3337c478bd9Sstevel@tonic-gate 	(void)login_init_entry(newli, pid, username, hostname, line, progname);
3347c478bd9Sstevel@tonic-gate 	return newli;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /* login_free_entry(struct logininfo *)    - free struct memory */
3397c478bd9Sstevel@tonic-gate void
login_free_entry(struct logininfo * li)3407c478bd9Sstevel@tonic-gate login_free_entry(struct logininfo *li)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	xfree(li);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate /* login_init_entry()
3477c478bd9Sstevel@tonic-gate  *                                        - initialise a struct logininfo
3487c478bd9Sstevel@tonic-gate  *
3497c478bd9Sstevel@tonic-gate  * Populates a new struct logininfo, a data structure meant to carry
3507c478bd9Sstevel@tonic-gate  * the information required to portably record login info.
3517c478bd9Sstevel@tonic-gate  *
3527c478bd9Sstevel@tonic-gate  * Returns: 1
3537c478bd9Sstevel@tonic-gate  */
3547c478bd9Sstevel@tonic-gate int
login_init_entry(struct logininfo * li,int pid,const char * username,const char * hostname,const char * line,const char * progname)3557c478bd9Sstevel@tonic-gate login_init_entry(struct logininfo *li, int pid, const char *username,
3567c478bd9Sstevel@tonic-gate 		 const char *hostname, const char *line, const char *progname)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	struct passwd *pw;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	(void) memset(li, 0, sizeof(*li));
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	li->pid = pid;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/* set the line information */
3657c478bd9Sstevel@tonic-gate 	if (line)
3667c478bd9Sstevel@tonic-gate 		(void) line_fullname(li->line, line, sizeof(li->line));
3677c478bd9Sstevel@tonic-gate 	else
3687c478bd9Sstevel@tonic-gate 		li->line_null = 1;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (progname)
3717c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->progname, progname, sizeof(li->progname));
3727c478bd9Sstevel@tonic-gate 	else
3737c478bd9Sstevel@tonic-gate 		li->progname_null = 1;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (username) {
3767c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->username, username, sizeof(li->username));
3777c478bd9Sstevel@tonic-gate 		pw = getpwnam(li->username);
3787c478bd9Sstevel@tonic-gate 		if (pw == NULL)
3797c478bd9Sstevel@tonic-gate 			fatal("login_init_entry: Cannot find user \"%s\"", li->username);
3807c478bd9Sstevel@tonic-gate 		li->uid = pw->pw_uid;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if (hostname)
3847c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->hostname, hostname, sizeof(li->hostname));
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return 1;
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /* login_set_current_time(struct logininfo *)    - set the current time
3907c478bd9Sstevel@tonic-gate  *
3917c478bd9Sstevel@tonic-gate  * Set the current time in a logininfo structure. This function is
3927c478bd9Sstevel@tonic-gate  * meant to eliminate the need to deal with system dependencies for
3937c478bd9Sstevel@tonic-gate  * time handling.
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate void
login_set_current_time(struct logininfo * li)3967c478bd9Sstevel@tonic-gate login_set_current_time(struct logininfo *li)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	struct timeval tv;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tv, NULL);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	li->tv_sec = tv.tv_sec;
4037c478bd9Sstevel@tonic-gate 	li->tv_usec = tv.tv_usec;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /* copy a sockaddr_* into our logininfo */
4077c478bd9Sstevel@tonic-gate void
login_set_addr(struct logininfo * li,const struct sockaddr * sa,const unsigned int sa_size)4087c478bd9Sstevel@tonic-gate login_set_addr(struct logininfo *li, const struct sockaddr *sa,
4097c478bd9Sstevel@tonic-gate 	       const unsigned int sa_size)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	unsigned int bufsize = sa_size;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/* make sure we don't overrun our union */
4147c478bd9Sstevel@tonic-gate 	if (sizeof(li->hostaddr) < sa_size)
4157c478bd9Sstevel@tonic-gate 		bufsize = sizeof(li->hostaddr);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate /**
4227c478bd9Sstevel@tonic-gate  ** login_write: Call low-level recording functions based on autoconf
4237c478bd9Sstevel@tonic-gate  ** results
4247c478bd9Sstevel@tonic-gate  **/
4257c478bd9Sstevel@tonic-gate int
login_write(struct logininfo * li)4267c478bd9Sstevel@tonic-gate login_write (struct logininfo *li)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate #ifndef HAVE_CYGWIN
4297c478bd9Sstevel@tonic-gate 	if ((int)geteuid() != 0) {
4307c478bd9Sstevel@tonic-gate 	  log("Attempt to write login records by non-root user (aborting)");
4317c478bd9Sstevel@tonic-gate 	  return 1;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate #endif
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/* set the timestamp */
4367c478bd9Sstevel@tonic-gate 	login_set_current_time(li);
4377c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN
4387c478bd9Sstevel@tonic-gate 	syslogin_write_entry(li);
4397c478bd9Sstevel@tonic-gate #endif
4407c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG
4417c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGIN) {
4427c478bd9Sstevel@tonic-gate 		(void) lastlog_write_entry(li);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate #endif
4457c478bd9Sstevel@tonic-gate #ifdef USE_UTMP
4467c478bd9Sstevel@tonic-gate 	utmp_write_entry(li);
4477c478bd9Sstevel@tonic-gate #endif
4487c478bd9Sstevel@tonic-gate #ifdef USE_WTMP
4497c478bd9Sstevel@tonic-gate 	wtmp_write_entry(li);
4507c478bd9Sstevel@tonic-gate #endif
4517c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX
4527c478bd9Sstevel@tonic-gate 	(void) utmpx_write_entry(li);
4537c478bd9Sstevel@tonic-gate #endif
4547c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX
4557c478bd9Sstevel@tonic-gate 	(void) wtmpx_write_entry(li);
4567c478bd9Sstevel@tonic-gate #endif
4577c478bd9Sstevel@tonic-gate 	return 0;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
460*2de0a7d6SDan McDonald /**
461*2de0a7d6SDan McDonald  ** getlast_entry: Call low-level functions to retrieve the last login
462*2de0a7d6SDan McDonald  **                time.
463*2de0a7d6SDan McDonald  **/
464*2de0a7d6SDan McDonald 
465*2de0a7d6SDan McDonald /* take the uid in li and return the last login time */
466*2de0a7d6SDan McDonald int
getlast_entry(struct logininfo * li)467*2de0a7d6SDan McDonald getlast_entry(struct logininfo *li)
468*2de0a7d6SDan McDonald {
469*2de0a7d6SDan McDonald #ifdef USE_LASTLOG
470*2de0a7d6SDan McDonald 	return(lastlog_get_entry(li));
471*2de0a7d6SDan McDonald #else /* !USE_LASTLOG */
472*2de0a7d6SDan McDonald 
473*2de0a7d6SDan McDonald #ifdef DISABLE_LASTLOG
474*2de0a7d6SDan McDonald 	/* On some systems we shouldn't even try to obtain last login
475*2de0a7d6SDan McDonald 	 * time, e.g. AIX */
476*2de0a7d6SDan McDonald 	return 0;
477*2de0a7d6SDan McDonald # else /* DISABLE_LASTLOG */
478*2de0a7d6SDan McDonald 	/* Try to retrieve the last login time from wtmp */
479*2de0a7d6SDan McDonald #  if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
480*2de0a7d6SDan McDonald 	/* retrieve last login time from utmp */
481*2de0a7d6SDan McDonald 	return (wtmp_get_entry(li));
482*2de0a7d6SDan McDonald #  else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
483*2de0a7d6SDan McDonald 	/* If wtmp isn't available, try wtmpx */
484*2de0a7d6SDan McDonald #   if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
485*2de0a7d6SDan McDonald 	/* retrieve last login time from utmpx */
486*2de0a7d6SDan McDonald 	return (wtmpx_get_entry(li));
487*2de0a7d6SDan McDonald #   else
488*2de0a7d6SDan McDonald 	/* Give up: No means of retrieving last login time */
489*2de0a7d6SDan McDonald 	return 0;
490*2de0a7d6SDan McDonald #   endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
491*2de0a7d6SDan McDonald #  endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
492*2de0a7d6SDan McDonald # endif /* DISABLE_LASTLOG */
493*2de0a7d6SDan McDonald #endif /* USE_LASTLOG */
494*2de0a7d6SDan McDonald }
495*2de0a7d6SDan McDonald 
496*2de0a7d6SDan McDonald 
497*2de0a7d6SDan McDonald 
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * 'line' string utility functions
5007c478bd9Sstevel@tonic-gate  *
5017c478bd9Sstevel@tonic-gate  * These functions process the 'line' string into one of three forms:
5027c478bd9Sstevel@tonic-gate  *
5037c478bd9Sstevel@tonic-gate  * 1. The full filename (including '/dev')
5047c478bd9Sstevel@tonic-gate  * 2. The stripped name (excluding '/dev')
5057c478bd9Sstevel@tonic-gate  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
5067c478bd9Sstevel@tonic-gate  *                               /dev/pts/1  -> ts/1 )
5077c478bd9Sstevel@tonic-gate  *
5087c478bd9Sstevel@tonic-gate  * Form 3 is used on some systems to identify a .tmp.? entry when
5097c478bd9Sstevel@tonic-gate  * attempting to remove it. Typically both addition and removal is
5107c478bd9Sstevel@tonic-gate  * performed by one application - say, sshd - so as long as the choice
5117c478bd9Sstevel@tonic-gate  * uniquely identifies a terminal it's ok.
5127c478bd9Sstevel@tonic-gate  */
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /* line_fullname(): add the leading '/dev/' if it doesn't exist make
5167c478bd9Sstevel@tonic-gate  * sure dst has enough space, if not just copy src (ugh) */
5177c478bd9Sstevel@tonic-gate char *
line_fullname(char * dst,const char * src,int dstsize)5187c478bd9Sstevel@tonic-gate line_fullname(char *dst, const char *src, int dstsize)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
5217c478bd9Sstevel@tonic-gate 	/* "sshd" is special, like "ftp" */
5227c478bd9Sstevel@tonic-gate 	if (strcmp(src, "sshd") ||
5237c478bd9Sstevel@tonic-gate 	    ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))) {
5247c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src, dstsize);
5257c478bd9Sstevel@tonic-gate 	} else {
5267c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, "/dev/", dstsize);
5277c478bd9Sstevel@tonic-gate 		(void) strlcat(dst, src, dstsize);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 	return dst;
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /* line_stripname(): strip the leading '/dev' if it exists, return dst */
5337c478bd9Sstevel@tonic-gate char *
line_stripname(char * dst,const char * src,int dstsize)5347c478bd9Sstevel@tonic-gate line_stripname(char *dst, const char *src, int dstsize)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
5377c478bd9Sstevel@tonic-gate 	if (strncmp(src, "/dev/", 5) == 0)
5387c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src + 5, dstsize);
5397c478bd9Sstevel@tonic-gate 	else
5407c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src, dstsize);
5417c478bd9Sstevel@tonic-gate 	return dst;
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /* line_abbrevname(): Return the abbreviated (usually four-character)
5457c478bd9Sstevel@tonic-gate  * form of the line (Just use the last <dstsize> characters of the
5467c478bd9Sstevel@tonic-gate  * full name.)
5477c478bd9Sstevel@tonic-gate  *
5487c478bd9Sstevel@tonic-gate  * NOTE: use strncpy because we do NOT necessarily want zero
5497c478bd9Sstevel@tonic-gate  * termination */
5507c478bd9Sstevel@tonic-gate char *
line_abbrevname(char * dst,const char * src,int dstsize)5517c478bd9Sstevel@tonic-gate line_abbrevname(char *dst, const char *src, int dstsize)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	size_t len;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	/* Always skip prefix if present */
5587c478bd9Sstevel@tonic-gate 	if (strncmp(src, "/dev/", 5) == 0)
5597c478bd9Sstevel@tonic-gate 		src += 5;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate #ifdef WITH_ABBREV_NO_TTY
5627c478bd9Sstevel@tonic-gate 	if (strncmp(src, "tty", 3) == 0)
5637c478bd9Sstevel@tonic-gate 		src += 3;
5647c478bd9Sstevel@tonic-gate #endif
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	len = strlen(src);
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	if (len > 0) {
5697c478bd9Sstevel@tonic-gate 		if (((int)len - dstsize) > 0)
5707c478bd9Sstevel@tonic-gate 			src +=  ((int)len - dstsize);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		/* note: _don't_ change this to strlcpy */
5737c478bd9Sstevel@tonic-gate 		(void) strncpy(dst, src, (size_t)dstsize);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	return dst;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /**
5807c478bd9Sstevel@tonic-gate  ** utmp utility functions
5817c478bd9Sstevel@tonic-gate  **
5827c478bd9Sstevel@tonic-gate  ** These functions manipulate struct utmp, taking system differences
5837c478bd9Sstevel@tonic-gate  ** into account.
5847c478bd9Sstevel@tonic-gate  **/
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate /* build the utmp structure */
5897c478bd9Sstevel@tonic-gate void
set_utmp_time(struct logininfo * li,struct utmp * ut)5907c478bd9Sstevel@tonic-gate set_utmp_time(struct logininfo *li, struct utmp *ut)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMP
5937c478bd9Sstevel@tonic-gate 	ut->ut_tv.tv_sec = li->tv_sec;
5947c478bd9Sstevel@tonic-gate 	ut->ut_tv.tv_usec = li->tv_usec;
5957c478bd9Sstevel@tonic-gate # else
5967c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMP
5977c478bd9Sstevel@tonic-gate 	ut->ut_time = li->tv_sec;
5987c478bd9Sstevel@tonic-gate #  endif
5997c478bd9Sstevel@tonic-gate # endif
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate void
construct_utmp(struct logininfo * li,struct utmp * ut)6037c478bd9Sstevel@tonic-gate construct_utmp(struct logininfo *li,
6047c478bd9Sstevel@tonic-gate 		    struct utmp *ut)
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate 	(void) memset(ut, '\0', sizeof(*ut));
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/* First fill out fields used for both logins and logouts */
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMP
6117c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
6127c478bd9Sstevel@tonic-gate # endif
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP
6157c478bd9Sstevel@tonic-gate 	/* This is done here to keep utmp constants out of struct logininfo */
6167c478bd9Sstevel@tonic-gate 	switch (li->type) {
6177c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
6187c478bd9Sstevel@tonic-gate 		ut->ut_type = USER_PROCESS;
6197c478bd9Sstevel@tonic-gate #ifdef _UNICOS
6207c478bd9Sstevel@tonic-gate 		cray_set_tmpdir(ut);
6217c478bd9Sstevel@tonic-gate #endif
6227c478bd9Sstevel@tonic-gate 		break;
6237c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
6247c478bd9Sstevel@tonic-gate 		ut->ut_type = DEAD_PROCESS;
6257c478bd9Sstevel@tonic-gate #ifdef _UNICOS
6267c478bd9Sstevel@tonic-gate 		cray_retain_utmp(ut, li->pid);
6277c478bd9Sstevel@tonic-gate #endif
6287c478bd9Sstevel@tonic-gate 		break;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate # endif
6317c478bd9Sstevel@tonic-gate 	set_utmp_time(li, ut);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	(void) line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate # ifdef HAVE_PID_IN_UTMP
6367c478bd9Sstevel@tonic-gate 	ut->ut_pid = li->pid;
6377c478bd9Sstevel@tonic-gate # endif
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	/* If we're logging out, leave all other fields blank */
6407c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGOUT)
6417c478bd9Sstevel@tonic-gate 	  return;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * These fields are only used when logging in, and are blank
6457c478bd9Sstevel@tonic-gate 	 * for logouts.
6467c478bd9Sstevel@tonic-gate 	 */
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	/* Use strncpy because we don't necessarily want null termination */
6497c478bd9Sstevel@tonic-gate 	(void) strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
6507c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP
6517c478bd9Sstevel@tonic-gate 	(void) strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
6527c478bd9Sstevel@tonic-gate # endif
6537c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMP
6547c478bd9Sstevel@tonic-gate 	/* this is just a 32-bit IP address */
6557c478bd9Sstevel@tonic-gate 	if (li->hostaddr.sa.sa_family == AF_INET)
6567c478bd9Sstevel@tonic-gate 		ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
6577c478bd9Sstevel@tonic-gate # endif
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /**
6627c478bd9Sstevel@tonic-gate  ** utmpx utility functions
6637c478bd9Sstevel@tonic-gate  **
6647c478bd9Sstevel@tonic-gate  ** These functions manipulate struct utmpx, accounting for system
6657c478bd9Sstevel@tonic-gate  ** variations.
6667c478bd9Sstevel@tonic-gate  **/
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate #if defined(USE_UTMPX) || defined (USE_WTMPX)
6697c478bd9Sstevel@tonic-gate /* build the utmpx structure */
6707c478bd9Sstevel@tonic-gate void
set_utmpx_time(struct logininfo * li,struct utmpx * utx)6717c478bd9Sstevel@tonic-gate set_utmpx_time(struct logininfo *li, struct utmpx *utx)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX
6747c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_sec = li->tv_sec;
6757c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_usec = li->tv_usec;
6767c478bd9Sstevel@tonic-gate # else /* HAVE_TV_IN_UTMPX */
6777c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMPX
6787c478bd9Sstevel@tonic-gate 	utx->ut_time = li->tv_sec;
6797c478bd9Sstevel@tonic-gate #  endif /* HAVE_TIME_IN_UTMPX */
6807c478bd9Sstevel@tonic-gate # endif /* HAVE_TV_IN_UTMPX */
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate void
construct_utmpx(struct logininfo * li,struct utmpx * utx)6847c478bd9Sstevel@tonic-gate construct_utmpx(struct logininfo *li, struct utmpx *utx)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate 	(void) memset(utx, '\0', sizeof(*utx));
6877c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX
6887c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
6897c478bd9Sstevel@tonic-gate # endif
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/* this is done here to keep utmp constants out of loginrec.h */
6927c478bd9Sstevel@tonic-gate 	switch (li->type) {
6937c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
6947c478bd9Sstevel@tonic-gate 		utx->ut_type = USER_PROCESS;
6957c478bd9Sstevel@tonic-gate 		break;
6967c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
6977c478bd9Sstevel@tonic-gate 		utx->ut_type = DEAD_PROCESS;
6987c478bd9Sstevel@tonic-gate 		break;
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 	if (!li->line_null)
7017c478bd9Sstevel@tonic-gate 		(void) line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
7027c478bd9Sstevel@tonic-gate 	else if (!li->progname_null)
7037c478bd9Sstevel@tonic-gate 		(void) line_stripname(utx->ut_line, li->progname, sizeof(utx->ut_line));
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	set_utmpx_time(li, utx);
7067c478bd9Sstevel@tonic-gate 	utx->ut_pid = li->pid;
7077c478bd9Sstevel@tonic-gate 	/* strncpy(): Don't necessarily want null termination */
7087c478bd9Sstevel@tonic-gate 	(void) strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGOUT)
7117c478bd9Sstevel@tonic-gate 		return;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/*
7147c478bd9Sstevel@tonic-gate 	 * These fields are only used when logging in, and are blank
7157c478bd9Sstevel@tonic-gate 	 * for logouts.
7167c478bd9Sstevel@tonic-gate 	 */
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX
7197c478bd9Sstevel@tonic-gate 	(void) strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
7207c478bd9Sstevel@tonic-gate # endif
7217c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMPX
7227c478bd9Sstevel@tonic-gate 	/* this is just a 32-bit IP address */
7237c478bd9Sstevel@tonic-gate 	if (li->hostaddr.sa.sa_family == AF_INET)
7247c478bd9Sstevel@tonic-gate 		utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
7257c478bd9Sstevel@tonic-gate # endif
7267c478bd9Sstevel@tonic-gate # ifdef HAVE_SYSLEN_IN_UTMPX
7277c478bd9Sstevel@tonic-gate 	/* ut_syslen is the length of the utx_host string */
7287c478bd9Sstevel@tonic-gate 	utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
7297c478bd9Sstevel@tonic-gate # endif
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX || USE_WTMPX */
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /**
7347c478bd9Sstevel@tonic-gate  ** Low-level utmp functions
7357c478bd9Sstevel@tonic-gate  **/
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /* FIXME: (ATL) utmp_write_direct needs testing */
7387c478bd9Sstevel@tonic-gate #ifdef USE_UTMP
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /* if we can, use pututline() etc. */
7417c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
7427c478bd9Sstevel@tonic-gate 	defined(HAVE_PUTUTLINE)
7437c478bd9Sstevel@tonic-gate #  define UTMP_USE_LIBRARY
7447c478bd9Sstevel@tonic-gate # endif
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate /* write a utmp entry with the system's help (pututline() and pals) */
7487c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
7497c478bd9Sstevel@tonic-gate static int
utmp_write_library(struct logininfo * li,struct utmp * ut)7507c478bd9Sstevel@tonic-gate utmp_write_library(struct logininfo *li, struct utmp *ut)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	setutent();
7537c478bd9Sstevel@tonic-gate 	pututline(ut);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate #  ifdef HAVE_ENDUTENT
7567c478bd9Sstevel@tonic-gate 	endutent();
7577c478bd9Sstevel@tonic-gate #  endif
7587c478bd9Sstevel@tonic-gate 	return 1;
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate # else /* UTMP_USE_LIBRARY */
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */
7637c478bd9Sstevel@tonic-gate /* This is a slightly modification of code in OpenBSD's login.c */
7647c478bd9Sstevel@tonic-gate static int
utmp_write_direct(struct logininfo * li,struct utmp * ut)7657c478bd9Sstevel@tonic-gate utmp_write_direct(struct logininfo *li, struct utmp *ut)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	struct utmp old_ut;
7687c478bd9Sstevel@tonic-gate 	register int fd;
7697c478bd9Sstevel@tonic-gate 	int tty;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* FIXME: (ATL) ttyslot() needs local implementation */
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate #if defined(HAVE_GETTTYENT)
7747c478bd9Sstevel@tonic-gate 	register struct ttyent *ty;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	tty=0;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	setttyent();
7797c478bd9Sstevel@tonic-gate 	while ((struct ttyent *)0 != (ty = getttyent())) {
7807c478bd9Sstevel@tonic-gate 		tty++;
7817c478bd9Sstevel@tonic-gate 		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
7827c478bd9Sstevel@tonic-gate 			break;
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 	endttyent();
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if((struct ttyent *)0 == ty) {
7877c478bd9Sstevel@tonic-gate 		log("utmp_write_entry: tty not found");
7887c478bd9Sstevel@tonic-gate 		return(1);
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate #else /* FIXME */
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate #endif /* HAVE_GETTTYENT */
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
7977c478bd9Sstevel@tonic-gate 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
7987c478bd9Sstevel@tonic-gate 		/*
7997c478bd9Sstevel@tonic-gate 		 * Prevent luser from zero'ing out ut_host.
8007c478bd9Sstevel@tonic-gate 		 * If the new ut_line is empty but the old one is not
8017c478bd9Sstevel@tonic-gate 		 * and ut_line and ut_name match, preserve the old ut_line.
8027c478bd9Sstevel@tonic-gate 		 */
8037c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
8047c478bd9Sstevel@tonic-gate 			(ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
8057c478bd9Sstevel@tonic-gate 			(strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
8067c478bd9Sstevel@tonic-gate 			(strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
8077c478bd9Sstevel@tonic-gate 			(void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
8117c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
8127c478bd9Sstevel@tonic-gate 			log("utmp_write_direct: error writing %s: %s",
8137c478bd9Sstevel@tonic-gate 			    UTMP_FILE, strerror(errno));
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 		(void)close(fd);
8167c478bd9Sstevel@tonic-gate 		return 1;
8177c478bd9Sstevel@tonic-gate 	} else {
8187c478bd9Sstevel@tonic-gate 		return 0;
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate # endif /* UTMP_USE_LIBRARY */
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static int
utmp_perform_login(struct logininfo * li)8247c478bd9Sstevel@tonic-gate utmp_perform_login(struct logininfo *li)
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	struct utmp ut;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
8297c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
8307c478bd9Sstevel@tonic-gate 	if (!utmp_write_library(li, &ut)) {
8317c478bd9Sstevel@tonic-gate 		log("utmp_perform_login: utmp_write_library() failed");
8327c478bd9Sstevel@tonic-gate 		return 0;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate # else
8357c478bd9Sstevel@tonic-gate 	if (!utmp_write_direct(li, &ut)) {
8367c478bd9Sstevel@tonic-gate 		log("utmp_perform_login: utmp_write_direct() failed");
8377c478bd9Sstevel@tonic-gate 		return 0;
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate # endif
8407c478bd9Sstevel@tonic-gate 	return 1;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate static int
utmp_perform_logout(struct logininfo * li)8457c478bd9Sstevel@tonic-gate utmp_perform_logout(struct logininfo *li)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	struct utmp ut;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
8507c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
8517c478bd9Sstevel@tonic-gate 	if (!utmp_write_library(li, &ut)) {
8527c478bd9Sstevel@tonic-gate 		log("utmp_perform_logout: utmp_write_library() failed");
8537c478bd9Sstevel@tonic-gate 		return 0;
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate # else
8567c478bd9Sstevel@tonic-gate 	if (!utmp_write_direct(li, &ut)) {
8577c478bd9Sstevel@tonic-gate 		log("utmp_perform_logout: utmp_write_direct() failed");
8587c478bd9Sstevel@tonic-gate 		return 0;
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate # endif
8617c478bd9Sstevel@tonic-gate 	return 1;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate int
utmp_write_entry(struct logininfo * li)8667c478bd9Sstevel@tonic-gate utmp_write_entry(struct logininfo *li)
8677c478bd9Sstevel@tonic-gate {
8687c478bd9Sstevel@tonic-gate 	if (li->line_null) {
8697c478bd9Sstevel@tonic-gate 		debug3("not writing utmp entry");
8707c478bd9Sstevel@tonic-gate 		return 1;
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 	debug3("writing utmp entry");
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	switch(li->type) {
8757c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
8767c478bd9Sstevel@tonic-gate 		return utmp_perform_login(li);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
8797c478bd9Sstevel@tonic-gate 		return utmp_perform_logout(li);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	default:
8827c478bd9Sstevel@tonic-gate 		log("utmp_write_entry: invalid type field");
8837c478bd9Sstevel@tonic-gate 		return 0;
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate #endif /* USE_UTMP */
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate /**
8907c478bd9Sstevel@tonic-gate  ** Low-level utmpx functions
8917c478bd9Sstevel@tonic-gate  **/
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate /* not much point if we don't want utmpx entries */
8947c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate /* if we have the wherewithall, use pututxline etc. */
8977c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
8987c478bd9Sstevel@tonic-gate 	defined(HAVE_PUTUTXLINE)
8997c478bd9Sstevel@tonic-gate #  define UTMPX_USE_LIBRARY
9007c478bd9Sstevel@tonic-gate # endif
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate /* write a utmpx entry with the system's help (pututxline() and pals) */
9047c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
9057c478bd9Sstevel@tonic-gate static int
utmpx_write_library(struct logininfo * li,struct utmpx * utx)9067c478bd9Sstevel@tonic-gate utmpx_write_library(struct logininfo *li, struct utmpx *utx)
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	setutxent();
9097c478bd9Sstevel@tonic-gate 	(void) pututxline(utx);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate #  ifdef HAVE_ENDUTXENT
9127c478bd9Sstevel@tonic-gate 	endutxent();
9137c478bd9Sstevel@tonic-gate #  endif
9147c478bd9Sstevel@tonic-gate 	return 1;
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate # else /* UTMPX_USE_LIBRARY */
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */
9207c478bd9Sstevel@tonic-gate static int
utmpx_write_direct(struct logininfo * li,struct utmpx * utx)9217c478bd9Sstevel@tonic-gate utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	log("utmpx_write_direct: not implemented!");
9247c478bd9Sstevel@tonic-gate 	return 0;
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate # endif /* UTMPX_USE_LIBRARY */
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate static int
utmpx_perform_login(struct logininfo * li)9297c478bd9Sstevel@tonic-gate utmpx_perform_login(struct logininfo *li)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	struct utmpx utx;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
9347c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
9357c478bd9Sstevel@tonic-gate 	if (!utmpx_write_library(li, &utx)) {
9367c478bd9Sstevel@tonic-gate 		log("tmpx_perform_login: utmp_write_library() failed");
9377c478bd9Sstevel@tonic-gate 		return 0;
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate # else
9407c478bd9Sstevel@tonic-gate 	if (!utmpx_write_direct(li, &ut)) {
9417c478bd9Sstevel@tonic-gate 		log("utmpx_perform_login: utmp_write_direct() failed");
9427c478bd9Sstevel@tonic-gate 		return 0;
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate # endif
9457c478bd9Sstevel@tonic-gate 	return 1;
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate static int
utmpx_perform_logout(struct logininfo * li)9507c478bd9Sstevel@tonic-gate utmpx_perform_logout(struct logininfo *li)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate 	struct utmpx utx;
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
9557c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX
9567c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
9577c478bd9Sstevel@tonic-gate # endif
9587c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX
9597c478bd9Sstevel@tonic-gate 	utx.ut_type = DEAD_PROCESS;
9607c478bd9Sstevel@tonic-gate # endif
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
9637c478bd9Sstevel@tonic-gate 	(void) utmpx_write_library(li, &utx);
9647c478bd9Sstevel@tonic-gate # else
9657c478bd9Sstevel@tonic-gate 	utmpx_write_direct(li, &utx);
9667c478bd9Sstevel@tonic-gate # endif
9677c478bd9Sstevel@tonic-gate 	return 1;
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate int
utmpx_write_entry(struct logininfo * li)9717c478bd9Sstevel@tonic-gate utmpx_write_entry(struct logininfo *li)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate 	if (li->line_null) {
9747c478bd9Sstevel@tonic-gate 		debug3("not writing utmpx entry");
9757c478bd9Sstevel@tonic-gate 		return 1;
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 	debug3("writing utmpx entry");
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	switch(li->type) {
9807c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
9817c478bd9Sstevel@tonic-gate 		return utmpx_perform_login(li);
9827c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
9837c478bd9Sstevel@tonic-gate 		return utmpx_perform_logout(li);
9847c478bd9Sstevel@tonic-gate 	default:
9857c478bd9Sstevel@tonic-gate 		log("utmpx_write_entry: invalid type field");
9867c478bd9Sstevel@tonic-gate 		return 0;
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX */
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /**
9937c478bd9Sstevel@tonic-gate  ** Low-level wtmp functions
9947c478bd9Sstevel@tonic-gate  **/
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate #ifdef USE_WTMP
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate /* write a wtmp entry direct to the end of the file */
9997c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */
10007c478bd9Sstevel@tonic-gate static int
wtmp_write(struct logininfo * li,struct utmp * ut)10017c478bd9Sstevel@tonic-gate wtmp_write(struct logininfo *li, struct utmp *ut)
10027c478bd9Sstevel@tonic-gate {
10037c478bd9Sstevel@tonic-gate 	struct stat buf;
10047c478bd9Sstevel@tonic-gate 	int fd, ret = 1;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
10077c478bd9Sstevel@tonic-gate 		log("wtmp_write: problem writing %s: %s",
10087c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
10097c478bd9Sstevel@tonic-gate 		return 0;
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == 0)
10127c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
10137c478bd9Sstevel@tonic-gate 			(void) ftruncate(fd, buf.st_size);
10147c478bd9Sstevel@tonic-gate 			log("wtmp_write: problem writing %s: %s",
10157c478bd9Sstevel@tonic-gate 			    WTMP_FILE, strerror(errno));
10167c478bd9Sstevel@tonic-gate 			ret = 0;
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 	(void)close(fd);
10197c478bd9Sstevel@tonic-gate 	return ret;
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate static int
wtmp_perform_login(struct logininfo * li)10237c478bd9Sstevel@tonic-gate wtmp_perform_login(struct logininfo *li)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	struct utmp ut;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
10287c478bd9Sstevel@tonic-gate 	return wtmp_write(li, &ut);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate static int
wtmp_perform_logout(struct logininfo * li)10337c478bd9Sstevel@tonic-gate wtmp_perform_logout(struct logininfo *li)
10347c478bd9Sstevel@tonic-gate {
10357c478bd9Sstevel@tonic-gate 	struct utmp ut;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
10387c478bd9Sstevel@tonic-gate 	return wtmp_write(li, &ut);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate int
wtmp_write_entry(struct logininfo * li)10437c478bd9Sstevel@tonic-gate wtmp_write_entry(struct logininfo *li)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	switch(li->type) {
10467c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
10477c478bd9Sstevel@tonic-gate 		return wtmp_perform_login(li);
10487c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
10497c478bd9Sstevel@tonic-gate 		return wtmp_perform_logout(li);
10507c478bd9Sstevel@tonic-gate 	default:
10517c478bd9Sstevel@tonic-gate 		log("wtmp_write_entry: invalid type field");
10527c478bd9Sstevel@tonic-gate 		return 0;
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate /* Notes on fetching login data from wtmp/wtmpx
10587c478bd9Sstevel@tonic-gate  *
10597c478bd9Sstevel@tonic-gate  * Logouts are usually recorded with (amongst other things) a blank
10607c478bd9Sstevel@tonic-gate  * username on a given tty line.  However, some systems (HP-UX is one)
10617c478bd9Sstevel@tonic-gate  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
10627c478bd9Sstevel@tonic-gate  *
10637c478bd9Sstevel@tonic-gate  * Since we're only looking for logins here, we know that the username
10647c478bd9Sstevel@tonic-gate  * must be set correctly. On systems that leave it in, we check for
10657c478bd9Sstevel@tonic-gate  * ut_type==USER_PROCESS (indicating a login.)
10667c478bd9Sstevel@tonic-gate  *
10677c478bd9Sstevel@tonic-gate  * Portability: Some systems may set something other than USER_PROCESS
10687c478bd9Sstevel@tonic-gate  * to indicate a login process. I don't know of any as I write. Also,
10697c478bd9Sstevel@tonic-gate  * it's possible that some systems may both leave the username in
10707c478bd9Sstevel@tonic-gate  * place and not have ut_type.
10717c478bd9Sstevel@tonic-gate  */
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate /* return true if this wtmp entry indicates a login */
10747c478bd9Sstevel@tonic-gate static int
wtmp_islogin(struct logininfo * li,struct utmp * ut)10757c478bd9Sstevel@tonic-gate wtmp_islogin(struct logininfo *li, struct utmp *ut)
10767c478bd9Sstevel@tonic-gate {
10777c478bd9Sstevel@tonic-gate 	if (strncmp(li->username, ut->ut_name,
10787c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
10797c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP
10807c478bd9Sstevel@tonic-gate 		if (ut->ut_type & USER_PROCESS)
10817c478bd9Sstevel@tonic-gate 			return 1;
10827c478bd9Sstevel@tonic-gate # else
10837c478bd9Sstevel@tonic-gate 		return 1;
10847c478bd9Sstevel@tonic-gate # endif
10857c478bd9Sstevel@tonic-gate 	}
10867c478bd9Sstevel@tonic-gate 	return 0;
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate int
wtmp_get_entry(struct logininfo * li)10907c478bd9Sstevel@tonic-gate wtmp_get_entry(struct logininfo *li)
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	struct stat st;
10937c478bd9Sstevel@tonic-gate 	struct utmp ut;
10947c478bd9Sstevel@tonic-gate 	int fd, found=0;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/* Clear the time entries in our logininfo */
10977c478bd9Sstevel@tonic-gate 	li->tv_sec = li->tv_usec = 0;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
11007c478bd9Sstevel@tonic-gate 		log("wtmp_get_entry: problem opening %s: %s",
11017c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
11027c478bd9Sstevel@tonic-gate 		return 0;
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 	if (fstat(fd, &st) != 0) {
11057c478bd9Sstevel@tonic-gate 		log("wtmp_get_entry: couldn't stat %s: %s",
11067c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
11077c478bd9Sstevel@tonic-gate 		(void) close(fd);
11087c478bd9Sstevel@tonic-gate 		return 0;
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/* Seek to the start of the last struct utmp */
11127c478bd9Sstevel@tonic-gate 	if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
11137c478bd9Sstevel@tonic-gate 		/* Looks like we've got a fresh wtmp file */
11147c478bd9Sstevel@tonic-gate 		(void) close(fd);
11157c478bd9Sstevel@tonic-gate 		return 0;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	while (!found) {
11197c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
11207c478bd9Sstevel@tonic-gate 			log("wtmp_get_entry: read of %s failed: %s",
11217c478bd9Sstevel@tonic-gate 			    WTMP_FILE, strerror(errno));
11227c478bd9Sstevel@tonic-gate 			(void) close (fd);
11237c478bd9Sstevel@tonic-gate 			return 0;
11247c478bd9Sstevel@tonic-gate 		}
11257c478bd9Sstevel@tonic-gate 		if ( wtmp_islogin(li, &ut) ) {
11267c478bd9Sstevel@tonic-gate 			found = 1;
11277c478bd9Sstevel@tonic-gate 			/* We've already checked for a time in struct
11287c478bd9Sstevel@tonic-gate 			 * utmp, in login_getlast(). */
11297c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMP
11307c478bd9Sstevel@tonic-gate 			li->tv_sec = ut.ut_time;
11317c478bd9Sstevel@tonic-gate # else
11327c478bd9Sstevel@tonic-gate #  if HAVE_TV_IN_UTMP
11337c478bd9Sstevel@tonic-gate 			li->tv_sec = ut.ut_tv.tv_sec;
11347c478bd9Sstevel@tonic-gate #  endif
11357c478bd9Sstevel@tonic-gate # endif
11367c478bd9Sstevel@tonic-gate 			(void) line_fullname(li->line, ut.ut_line,
11377c478bd9Sstevel@tonic-gate 				      MIN_SIZEOF(li->line, ut.ut_line));
11387c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP
11397c478bd9Sstevel@tonic-gate 			(void) strlcpy(li->hostname, ut.ut_host,
11407c478bd9Sstevel@tonic-gate 				MIN_SIZEOF(li->hostname, ut.ut_host));
11417c478bd9Sstevel@tonic-gate # endif
11427c478bd9Sstevel@tonic-gate 			continue;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 		/* Seek back 2 x struct utmp */
11457c478bd9Sstevel@tonic-gate 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
11467c478bd9Sstevel@tonic-gate 			/* We've found the start of the file, so quit */
11477c478bd9Sstevel@tonic-gate 			(void) close (fd);
11487c478bd9Sstevel@tonic-gate 			return 0;
11497c478bd9Sstevel@tonic-gate 		}
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	/* We found an entry. Tidy up and return */
11537c478bd9Sstevel@tonic-gate 	(void) close(fd);
11547c478bd9Sstevel@tonic-gate 	return 1;
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate # endif /* USE_WTMP */
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate /**
11607c478bd9Sstevel@tonic-gate  ** Low-level wtmpx functions
11617c478bd9Sstevel@tonic-gate  **/
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX
11647c478bd9Sstevel@tonic-gate /* write a wtmpx entry direct to the end of the file */
11657c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */
11667c478bd9Sstevel@tonic-gate static int
wtmpx_write(struct logininfo * li,struct utmpx * utx)11677c478bd9Sstevel@tonic-gate wtmpx_write(struct logininfo *li, struct utmpx *utx)
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate 	struct stat buf;
11707c478bd9Sstevel@tonic-gate 	int fd, ret = 1;
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
11737c478bd9Sstevel@tonic-gate 		log("wtmpx_write: problem opening %s: %s",
11747c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
11757c478bd9Sstevel@tonic-gate 		return 0;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == 0)
11797c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
11807c478bd9Sstevel@tonic-gate 			(void) ftruncate(fd, buf.st_size);
11817c478bd9Sstevel@tonic-gate 			log("wtmpx_write: problem writing %s: %s",
11827c478bd9Sstevel@tonic-gate 			    WTMPX_FILE, strerror(errno));
11837c478bd9Sstevel@tonic-gate 			ret = 0;
11847c478bd9Sstevel@tonic-gate 		}
11857c478bd9Sstevel@tonic-gate 	(void)close(fd);
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	return ret;
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate static int
wtmpx_perform_login(struct logininfo * li)11927c478bd9Sstevel@tonic-gate wtmpx_perform_login(struct logininfo *li)
11937c478bd9Sstevel@tonic-gate {
11947c478bd9Sstevel@tonic-gate 	struct utmpx utx;
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
11977c478bd9Sstevel@tonic-gate 	return wtmpx_write(li, &utx);
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate static int
wtmpx_perform_logout(struct logininfo * li)12027c478bd9Sstevel@tonic-gate wtmpx_perform_logout(struct logininfo *li)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate 	struct utmpx utx;
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
12077c478bd9Sstevel@tonic-gate 	return wtmpx_write(li, &utx);
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate int
wtmpx_write_entry(struct logininfo * li)12127c478bd9Sstevel@tonic-gate wtmpx_write_entry(struct logininfo *li)
12137c478bd9Sstevel@tonic-gate {
12147c478bd9Sstevel@tonic-gate 	switch(li->type) {
12157c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
12167c478bd9Sstevel@tonic-gate 		return wtmpx_perform_login(li);
12177c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
12187c478bd9Sstevel@tonic-gate 		return wtmpx_perform_logout(li);
12197c478bd9Sstevel@tonic-gate 	default:
12207c478bd9Sstevel@tonic-gate 		log("wtmpx_write_entry: invalid type field");
12217c478bd9Sstevel@tonic-gate 		return 0;
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate /* Please see the notes above wtmp_islogin() for information about the
12267c478bd9Sstevel@tonic-gate    next two functions */
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate /* Return true if this wtmpx entry indicates a login */
12297c478bd9Sstevel@tonic-gate static int
wtmpx_islogin(struct logininfo * li,struct utmpx * utx)12307c478bd9Sstevel@tonic-gate wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	if ( strncmp(li->username, utx->ut_name,
12337c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
12347c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX
12357c478bd9Sstevel@tonic-gate 		if (utx->ut_type == USER_PROCESS)
12367c478bd9Sstevel@tonic-gate 			return 1;
12377c478bd9Sstevel@tonic-gate # else
12387c478bd9Sstevel@tonic-gate 		return 1;
12397c478bd9Sstevel@tonic-gate # endif
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 	return 0;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate #if 0
12467c478bd9Sstevel@tonic-gate int
12477c478bd9Sstevel@tonic-gate wtmpx_get_entry(struct logininfo *li)
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate 	struct stat st;
12507c478bd9Sstevel@tonic-gate 	struct utmpx utx;
12517c478bd9Sstevel@tonic-gate 	int fd, found=0;
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	/* Clear the time entries */
12547c478bd9Sstevel@tonic-gate 	li->tv_sec = li->tv_usec = 0;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
12577c478bd9Sstevel@tonic-gate 		log("wtmpx_get_entry: problem opening %s: %s",
12587c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
12597c478bd9Sstevel@tonic-gate 		return 0;
12607c478bd9Sstevel@tonic-gate 	}
12617c478bd9Sstevel@tonic-gate 	if (fstat(fd, &st) != 0) {
12627c478bd9Sstevel@tonic-gate 		log("wtmpx_get_entry: couldn't stat %s: %s",
12637c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
12647c478bd9Sstevel@tonic-gate 		(void) close(fd);
12657c478bd9Sstevel@tonic-gate 		return 0;
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	/* Seek to the start of the last struct utmpx */
12697c478bd9Sstevel@tonic-gate 	if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
12707c478bd9Sstevel@tonic-gate 		/* probably a newly rotated wtmpx file */
12717c478bd9Sstevel@tonic-gate 		(void) close(fd);
12727c478bd9Sstevel@tonic-gate 		return 0;
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	while (!found) {
12767c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
12777c478bd9Sstevel@tonic-gate 			log("wtmpx_get_entry: read of %s failed: %s",
12787c478bd9Sstevel@tonic-gate 			    WTMPX_FILE, strerror(errno));
12797c478bd9Sstevel@tonic-gate 			(void) close (fd);
12807c478bd9Sstevel@tonic-gate 			return 0;
12817c478bd9Sstevel@tonic-gate 		}
12827c478bd9Sstevel@tonic-gate 		/* Logouts are recorded as a blank username on a particular line.
12837c478bd9Sstevel@tonic-gate 		 * So, we just need to find the username in struct utmpx */
12847c478bd9Sstevel@tonic-gate 		if ( wtmpx_islogin(li, &utx) ) {
12857c478bd9Sstevel@tonic-gate 			found = 1;
12867c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX
12877c478bd9Sstevel@tonic-gate 			li->tv_sec = utx.ut_tv.tv_sec;
12887c478bd9Sstevel@tonic-gate # else
12897c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMPX
12907c478bd9Sstevel@tonic-gate 			li->tv_sec = utx.ut_time;
12917c478bd9Sstevel@tonic-gate #  endif
12927c478bd9Sstevel@tonic-gate # endif
12937c478bd9Sstevel@tonic-gate 			(void) line_fullname(li->line, utx.ut_line, sizeof(li->line));
12947c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX
12957c478bd9Sstevel@tonic-gate 			(void) strlcpy(li->hostname, utx.ut_host,
12967c478bd9Sstevel@tonic-gate 				MIN_SIZEOF(li->hostname, utx.ut_host));
12977c478bd9Sstevel@tonic-gate # endif
12987c478bd9Sstevel@tonic-gate 			continue;
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
13017c478bd9Sstevel@tonic-gate 			(void) close (fd);
13027c478bd9Sstevel@tonic-gate 			return 0;
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	(void) close(fd);
13077c478bd9Sstevel@tonic-gate 	return 1;
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate #endif
13107c478bd9Sstevel@tonic-gate #endif /* USE_WTMPX */
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate /**
13137c478bd9Sstevel@tonic-gate  ** Low-level libutil login() functions
13147c478bd9Sstevel@tonic-gate  **/
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN
13177c478bd9Sstevel@tonic-gate static int
syslogin_perform_login(struct logininfo * li)13187c478bd9Sstevel@tonic-gate syslogin_perform_login(struct logininfo *li)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate 	struct utmp *ut;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
13237c478bd9Sstevel@tonic-gate 		log("syslogin_perform_login: couldn't malloc()");
13247c478bd9Sstevel@tonic-gate 		return 0;
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 	construct_utmp(li, ut);
13277c478bd9Sstevel@tonic-gate 	login(ut);
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	return 1;
13307c478bd9Sstevel@tonic-gate }
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate static int
syslogin_perform_logout(struct logininfo * li)13337c478bd9Sstevel@tonic-gate syslogin_perform_logout(struct logininfo *li)
13347c478bd9Sstevel@tonic-gate {
13357c478bd9Sstevel@tonic-gate # ifdef HAVE_LOGOUT
13367c478bd9Sstevel@tonic-gate 	char line[8];
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	(void)line_stripname(line, li->line, sizeof(line));
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (!logout(line)) {
13417c478bd9Sstevel@tonic-gate 		log("syslogin_perform_logout: logout() returned an error");
13427c478bd9Sstevel@tonic-gate #  ifdef HAVE_LOGWTMP
13437c478bd9Sstevel@tonic-gate 	} else {
13447c478bd9Sstevel@tonic-gate 		logwtmp(line, "", "");
13457c478bd9Sstevel@tonic-gate #  endif
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 	/* FIXME: (ATL - if the need arises) What to do if we have
13487c478bd9Sstevel@tonic-gate 	 * login, but no logout?  what if logout but no logwtmp? All
13497c478bd9Sstevel@tonic-gate 	 * routines are in libutil so they should all be there,
13507c478bd9Sstevel@tonic-gate 	 * but... */
13517c478bd9Sstevel@tonic-gate # endif
13527c478bd9Sstevel@tonic-gate 	return 1;
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate int
syslogin_write_entry(struct logininfo * li)13567c478bd9Sstevel@tonic-gate syslogin_write_entry(struct logininfo *li)
13577c478bd9Sstevel@tonic-gate {
13587c478bd9Sstevel@tonic-gate 	switch (li->type) {
13597c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
13607c478bd9Sstevel@tonic-gate 		return syslogin_perform_login(li);
13617c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
13627c478bd9Sstevel@tonic-gate 		return syslogin_perform_logout(li);
13637c478bd9Sstevel@tonic-gate 	default:
13647c478bd9Sstevel@tonic-gate 		log("syslogin_write_entry: Invalid type field");
13657c478bd9Sstevel@tonic-gate 		return 0;
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate #endif /* USE_LOGIN */
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate /* end of file log-syslogin.c */
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate /**
13737c478bd9Sstevel@tonic-gate  ** Low-level lastlog functions
13747c478bd9Sstevel@tonic-gate  **/
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG
13777c478bd9Sstevel@tonic-gate #define LL_FILE 1
13787c478bd9Sstevel@tonic-gate #define LL_DIR 2
13797c478bd9Sstevel@tonic-gate #define LL_OTHER 3
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate static void
lastlog_construct(struct logininfo * li,struct lastlog * last)13827c478bd9Sstevel@tonic-gate lastlog_construct(struct logininfo *li, struct lastlog *last)
13837c478bd9Sstevel@tonic-gate {
13847c478bd9Sstevel@tonic-gate 	/* clear the structure */
13857c478bd9Sstevel@tonic-gate 	(void) memset(last, '\0', sizeof(*last));
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
13887c478bd9Sstevel@tonic-gate 	(void) strlcpy(last->ll_host, li->hostname,
13897c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(last->ll_host, li->hostname));
13907c478bd9Sstevel@tonic-gate 	last->ll_time = li->tv_sec;
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate static int
lastlog_filetype(char * filename)13947c478bd9Sstevel@tonic-gate lastlog_filetype(char *filename)
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate 	struct stat st;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	if (stat(LASTLOG_FILE, &st) != 0) {
13997c478bd9Sstevel@tonic-gate 		log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
14007c478bd9Sstevel@tonic-gate 			strerror(errno));
14017c478bd9Sstevel@tonic-gate 		return 0;
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 	if (S_ISDIR(st.st_mode))
14047c478bd9Sstevel@tonic-gate 		return LL_DIR;
14057c478bd9Sstevel@tonic-gate 	else if (S_ISREG(st.st_mode))
14067c478bd9Sstevel@tonic-gate 		return LL_FILE;
14077c478bd9Sstevel@tonic-gate 	else
14087c478bd9Sstevel@tonic-gate 		return LL_OTHER;
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate /* open the file (using filemode) and seek to the login entry */
14137c478bd9Sstevel@tonic-gate static int
lastlog_openseek(struct logininfo * li,int * fd,int filemode)14147c478bd9Sstevel@tonic-gate lastlog_openseek(struct logininfo *li, int *fd, int filemode)
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate 	off_t offset;
14177c478bd9Sstevel@tonic-gate 	int type;
14187c478bd9Sstevel@tonic-gate 	char lastlog_file[1024];
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	type = lastlog_filetype(LASTLOG_FILE);
14217c478bd9Sstevel@tonic-gate 	switch (type) {
14227c478bd9Sstevel@tonic-gate 		case LL_FILE:
14237c478bd9Sstevel@tonic-gate 			(void) strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
14247c478bd9Sstevel@tonic-gate 			break;
14257c478bd9Sstevel@tonic-gate 		case LL_DIR:
14267c478bd9Sstevel@tonic-gate 			(void) snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
14277c478bd9Sstevel@tonic-gate 				 LASTLOG_FILE, li->username);
14287c478bd9Sstevel@tonic-gate 			break;
14297c478bd9Sstevel@tonic-gate 		default:
14307c478bd9Sstevel@tonic-gate 			log("lastlog_openseek: %.100s is not a file or directory!",
14317c478bd9Sstevel@tonic-gate 			    LASTLOG_FILE);
14327c478bd9Sstevel@tonic-gate 			return 0;
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	*fd = open(lastlog_file, filemode);
14367c478bd9Sstevel@tonic-gate 	if ( *fd < 0) {
14377c478bd9Sstevel@tonic-gate 		debug("lastlog_openseek: Couldn't open %s: %s",
14387c478bd9Sstevel@tonic-gate 		    lastlog_file, strerror(errno));
14397c478bd9Sstevel@tonic-gate 		return 0;
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	if (type == LL_FILE) {
14437c478bd9Sstevel@tonic-gate 		/* find this uid's offset in the lastlog file */
14447c478bd9Sstevel@tonic-gate 		offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 		if ( lseek(*fd, offset, SEEK_SET) != offset ) {
14477c478bd9Sstevel@tonic-gate 			log("lastlog_openseek: %s->lseek(): %s",
14487c478bd9Sstevel@tonic-gate 			 lastlog_file, strerror(errno));
14497c478bd9Sstevel@tonic-gate 			return 0;
14507c478bd9Sstevel@tonic-gate 		}
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	return 1;
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate static int
lastlog_perform_login(struct logininfo * li)14577c478bd9Sstevel@tonic-gate lastlog_perform_login(struct logininfo *li)
14587c478bd9Sstevel@tonic-gate {
14597c478bd9Sstevel@tonic-gate 	struct lastlog last;
14607c478bd9Sstevel@tonic-gate 	int fd;
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	/* create our struct lastlog */
14637c478bd9Sstevel@tonic-gate 	lastlog_construct(li, &last);
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
14667c478bd9Sstevel@tonic-gate 		return(0);
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	/* write the entry */
14697c478bd9Sstevel@tonic-gate 	if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
14707c478bd9Sstevel@tonic-gate 		(void) close(fd);
14717c478bd9Sstevel@tonic-gate 		log("lastlog_write_filemode: Error writing to %s: %s",
14727c478bd9Sstevel@tonic-gate 		    LASTLOG_FILE, strerror(errno));
14737c478bd9Sstevel@tonic-gate 		return 0;
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	(void) close(fd);
14777c478bd9Sstevel@tonic-gate 	return 1;
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate int
lastlog_write_entry(struct logininfo * li)14817c478bd9Sstevel@tonic-gate lastlog_write_entry(struct logininfo *li)
14827c478bd9Sstevel@tonic-gate {
14837c478bd9Sstevel@tonic-gate 	switch(li->type) {
14847c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
14857c478bd9Sstevel@tonic-gate 		return lastlog_perform_login(li);
14867c478bd9Sstevel@tonic-gate 	default:
14877c478bd9Sstevel@tonic-gate 		log("lastlog_write_entry: Invalid type field");
14887c478bd9Sstevel@tonic-gate 		return 0;
14897c478bd9Sstevel@tonic-gate 	}
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate static void
lastlog_populate_entry(struct logininfo * li,struct lastlog * last)14937c478bd9Sstevel@tonic-gate lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
14947c478bd9Sstevel@tonic-gate {
14957c478bd9Sstevel@tonic-gate 	(void) line_fullname(li->line, last->ll_line, sizeof(li->line));
14967c478bd9Sstevel@tonic-gate 	(void) strlcpy(li->hostname, last->ll_host,
14977c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->hostname, last->ll_host));
14987c478bd9Sstevel@tonic-gate 	li->tv_sec = last->ll_time;
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate int
lastlog_get_entry(struct logininfo * li)15027c478bd9Sstevel@tonic-gate lastlog_get_entry(struct logininfo *li)
15037c478bd9Sstevel@tonic-gate {
15047c478bd9Sstevel@tonic-gate 	struct lastlog last;
150537286d25Sjp161948 	int fd, ret;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	if (!lastlog_openseek(li, &fd, O_RDONLY))
150837286d25Sjp161948 		return (0);
15097c478bd9Sstevel@tonic-gate 
151037286d25Sjp161948 	ret = atomicio(read, fd, &last, sizeof(last));
151137286d25Sjp161948 	close(fd);
151237286d25Sjp161948 
151337286d25Sjp161948 	switch (ret) {
151437286d25Sjp161948 	case 0:
151537286d25Sjp161948 		memset(&last, '\0', sizeof(last));
151637286d25Sjp161948 		/* FALLTHRU */
151737286d25Sjp161948 	case sizeof(last):
151837286d25Sjp161948 		lastlog_populate_entry(li, &last);
151937286d25Sjp161948 		return (1);
152037286d25Sjp161948 	case -1:
152137286d25Sjp161948 		error("%s: Error reading from %s: %s", __func__,
15227c478bd9Sstevel@tonic-gate 		    LASTLOG_FILE, strerror(errno));
152337286d25Sjp161948 		return (0);
152437286d25Sjp161948 	default:
152537286d25Sjp161948 		error("%s: Error reading from %s: Expecting %d, got %d",
152637286d25Sjp161948 		    __func__, LASTLOG_FILE, (int)sizeof(last), ret);
152737286d25Sjp161948 		return (0);
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 
153037286d25Sjp161948 	/* NOTREACHED */
153137286d25Sjp161948 	return (0);
15327c478bd9Sstevel@tonic-gate }
15337c478bd9Sstevel@tonic-gate #endif /* USE_LASTLOG */
1534