xref: /freebsd/crypto/openssh/loginrec.c (revision e73e9afa91f5b9a483863ad8e01f6843c8e11fcb)
183d2307dSDag-Erling Smørgrav /*
283d2307dSDag-Erling Smørgrav  * Copyright (c) 2000 Andre Lucas.  All rights reserved.
383d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1998 Todd C. Miller
483d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1996 Jason Downs
583d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1996 Theo de Raadt
683d2307dSDag-Erling Smørgrav  *
783d2307dSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
883d2307dSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
983d2307dSDag-Erling Smørgrav  * are met:
1083d2307dSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1183d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1283d2307dSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1383d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1483d2307dSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1583d2307dSDag-Erling Smørgrav  * 3. All advertising materials mentioning features or use of this software
1683d2307dSDag-Erling Smørgrav  *    must display the following acknowledgement:
1783d2307dSDag-Erling Smørgrav  *      This product includes software developed by Markus Friedl.
1883d2307dSDag-Erling Smørgrav  * 4. The name of the author may not be used to endorse or promote products
1983d2307dSDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
2083d2307dSDag-Erling Smørgrav  *
2183d2307dSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2283d2307dSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2383d2307dSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2483d2307dSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2583d2307dSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2683d2307dSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2783d2307dSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2883d2307dSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2983d2307dSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3083d2307dSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3183d2307dSDag-Erling Smørgrav  */
3283d2307dSDag-Erling Smørgrav 
3383d2307dSDag-Erling Smørgrav /**
3483d2307dSDag-Erling Smørgrav  ** loginrec.c:  platform-independent login recording and lastlog retrieval
3583d2307dSDag-Erling Smørgrav  **/
3683d2307dSDag-Erling Smørgrav 
3783d2307dSDag-Erling Smørgrav /*
3883d2307dSDag-Erling Smørgrav   The new login code explained
3983d2307dSDag-Erling Smørgrav   ============================
4083d2307dSDag-Erling Smørgrav 
4183d2307dSDag-Erling Smørgrav   This code attempts to provide a common interface to login recording
4283d2307dSDag-Erling Smørgrav   (utmp and friends) and last login time retrieval.
4383d2307dSDag-Erling Smørgrav 
4483d2307dSDag-Erling Smørgrav   Its primary means of achieving this is to use 'struct logininfo', a
4583d2307dSDag-Erling Smørgrav   union of all the useful fields in the various different types of
4683d2307dSDag-Erling Smørgrav   system login record structures one finds on UNIX variants.
4783d2307dSDag-Erling Smørgrav 
4883d2307dSDag-Erling Smørgrav   We depend on autoconf to define which recording methods are to be
4983d2307dSDag-Erling Smørgrav   used, and which fields are contained in the relevant data structures
5083d2307dSDag-Erling Smørgrav   on the local system. Many C preprocessor symbols affect which code
5183d2307dSDag-Erling Smørgrav   gets compiled here.
5283d2307dSDag-Erling Smørgrav 
5383d2307dSDag-Erling Smørgrav   The code is designed to make it easy to modify a particular
5483d2307dSDag-Erling Smørgrav   recording method, without affecting other methods nor requiring so
5583d2307dSDag-Erling Smørgrav   many nested conditional compilation blocks as were commonplace in
5683d2307dSDag-Erling Smørgrav   the old code.
5783d2307dSDag-Erling Smørgrav 
5883d2307dSDag-Erling Smørgrav   For login recording, we try to use the local system's libraries as
5983d2307dSDag-Erling Smørgrav   these are clearly most likely to work correctly. For utmp systems
6083d2307dSDag-Erling Smørgrav   this usually means login() and logout() or setutent() etc., probably
6183d2307dSDag-Erling Smørgrav   in libutil, along with logwtmp() etc. On these systems, we fall back
6283d2307dSDag-Erling Smørgrav   to writing the files directly if we have to, though this method
6383d2307dSDag-Erling Smørgrav   requires very thorough testing so we do not corrupt local auditing
6483d2307dSDag-Erling Smørgrav   information. These files and their access methods are very system
6583d2307dSDag-Erling Smørgrav   specific indeed.
6683d2307dSDag-Erling Smørgrav 
6783d2307dSDag-Erling Smørgrav   For utmpx systems, the corresponding library functions are
6883d2307dSDag-Erling Smørgrav   setutxent() etc. To the author's knowledge, all utmpx systems have
6983d2307dSDag-Erling Smørgrav   these library functions and so no direct write is attempted. If such
7083d2307dSDag-Erling Smørgrav   a system exists and needs support, direct analogues of the [uw]tmp
7183d2307dSDag-Erling Smørgrav   code should suffice.
7283d2307dSDag-Erling Smørgrav 
7383d2307dSDag-Erling Smørgrav   Retrieving the time of last login ('lastlog') is in some ways even
7483d2307dSDag-Erling Smørgrav   more problemmatic than login recording. Some systems provide a
7583d2307dSDag-Erling Smørgrav   simple table of all users which we seek based on uid and retrieve a
7683d2307dSDag-Erling Smørgrav   relatively standard structure. Others record the same information in
7783d2307dSDag-Erling Smørgrav   a directory with a separate file, and others don't record the
7883d2307dSDag-Erling Smørgrav   information separately at all. For systems in the latter category,
7983d2307dSDag-Erling Smørgrav   we look backwards in the wtmp or wtmpx file for the last login entry
8083d2307dSDag-Erling Smørgrav   for our user. Naturally this is slower and on busy systems could
8183d2307dSDag-Erling Smørgrav   incur a significant performance penalty.
8283d2307dSDag-Erling Smørgrav 
8383d2307dSDag-Erling Smørgrav   Calling the new code
8483d2307dSDag-Erling Smørgrav   --------------------
8583d2307dSDag-Erling Smørgrav 
8683d2307dSDag-Erling Smørgrav   In OpenSSH all login recording and retrieval is performed in
8783d2307dSDag-Erling Smørgrav   login.c. Here you'll find working examples. Also, in the logintest.c
8883d2307dSDag-Erling Smørgrav   program there are more examples.
8983d2307dSDag-Erling Smørgrav 
9083d2307dSDag-Erling Smørgrav   Internal handler calling method
9183d2307dSDag-Erling Smørgrav   -------------------------------
9283d2307dSDag-Erling Smørgrav 
9383d2307dSDag-Erling Smørgrav   When a call is made to login_login() or login_logout(), both
9483d2307dSDag-Erling Smørgrav   routines set a struct logininfo flag defining which action (log in,
9583d2307dSDag-Erling Smørgrav   or log out) is to be taken. They both then call login_write(), which
9683d2307dSDag-Erling Smørgrav   calls whichever of the many structure-specific handlers autoconf
9783d2307dSDag-Erling Smørgrav   selects for the local system.
9883d2307dSDag-Erling Smørgrav 
9983d2307dSDag-Erling Smørgrav   The handlers themselves handle system data structure specifics. Both
10083d2307dSDag-Erling Smørgrav   struct utmp and struct utmpx have utility functions (see
10183d2307dSDag-Erling Smørgrav   construct_utmp*()) to try to make it simpler to add extra systems
10283d2307dSDag-Erling Smørgrav   that introduce new features to either structure.
10383d2307dSDag-Erling Smørgrav 
10483d2307dSDag-Erling Smørgrav   While it may seem terribly wasteful to replicate so much similar
10583d2307dSDag-Erling Smørgrav   code for each method, experience has shown that maintaining code to
10683d2307dSDag-Erling Smørgrav   write both struct utmp and utmpx in one function, whilst maintaining
10783d2307dSDag-Erling Smørgrav   support for all systems whether they have library support or not, is
10883d2307dSDag-Erling Smørgrav   a difficult and time-consuming task.
10983d2307dSDag-Erling Smørgrav 
11083d2307dSDag-Erling Smørgrav   Lastlog support proceeds similarly. Functions login_get_lastlog()
11183d2307dSDag-Erling Smørgrav   (and its OpenSSH-tuned friend login_get_lastlog_time()) call
11283d2307dSDag-Erling Smørgrav   getlast_entry(), which tries one of three methods to find the last
11383d2307dSDag-Erling Smørgrav   login time. It uses local system lastlog support if it can,
11483d2307dSDag-Erling Smørgrav   otherwise it tries wtmp or wtmpx before giving up and returning 0,
11583d2307dSDag-Erling Smørgrav   meaning "tilt".
11683d2307dSDag-Erling Smørgrav 
11783d2307dSDag-Erling Smørgrav   Maintenance
11883d2307dSDag-Erling Smørgrav   -----------
11983d2307dSDag-Erling Smørgrav 
12083d2307dSDag-Erling Smørgrav   In many cases it's possible to tweak autoconf to select the correct
12183d2307dSDag-Erling Smørgrav   methods for a particular platform, either by improving the detection
12283d2307dSDag-Erling Smørgrav   code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
12383d2307dSDag-Erling Smørgrav   symbols for the platform.
12483d2307dSDag-Erling Smørgrav 
12583d2307dSDag-Erling Smørgrav   Use logintest to check which symbols are defined before modifying
12683d2307dSDag-Erling Smørgrav   configure.ac and loginrec.c. (You have to build logintest yourself
12783d2307dSDag-Erling Smørgrav   with 'make logintest' as it's not built by default.)
12883d2307dSDag-Erling Smørgrav 
12983d2307dSDag-Erling Smørgrav   Otherwise, patches to the specific method(s) are very helpful!
13083d2307dSDag-Erling Smørgrav 
13183d2307dSDag-Erling Smørgrav */
13283d2307dSDag-Erling Smørgrav 
13383d2307dSDag-Erling Smørgrav /**
13483d2307dSDag-Erling Smørgrav  ** TODO:
13583d2307dSDag-Erling Smørgrav  **   homegrown ttyslot()
13683d2307dSDag-Erling Smørgrav  **   test, test, test
13783d2307dSDag-Erling Smørgrav  **
13883d2307dSDag-Erling Smørgrav  ** Platform status:
13983d2307dSDag-Erling Smørgrav  ** ----------------
14083d2307dSDag-Erling Smørgrav  **
14183d2307dSDag-Erling Smørgrav  ** Known good:
14283d2307dSDag-Erling Smørgrav  **   Linux (Redhat 6.2, Debian)
14383d2307dSDag-Erling Smørgrav  **   Solaris
14483d2307dSDag-Erling Smørgrav  **   HP-UX 10.20 (gcc only)
14583d2307dSDag-Erling Smørgrav  **   IRIX
14683d2307dSDag-Erling Smørgrav  **   NeXT - M68k/HPPA/Sparc (4.2/3.3)
14783d2307dSDag-Erling Smørgrav  **
14883d2307dSDag-Erling Smørgrav  ** Testing required: Please send reports!
14983d2307dSDag-Erling Smørgrav  **   NetBSD
15083d2307dSDag-Erling Smørgrav  **   HP-UX 11
15183d2307dSDag-Erling Smørgrav  **   AIX
15283d2307dSDag-Erling Smørgrav  **
15383d2307dSDag-Erling Smørgrav  ** Platforms with known problems:
15483d2307dSDag-Erling Smørgrav  **   Some variants of Slackware Linux
15583d2307dSDag-Erling Smørgrav  **
15683d2307dSDag-Erling Smørgrav  **/
15783d2307dSDag-Erling Smørgrav 
15883d2307dSDag-Erling Smørgrav #include "includes.h"
15983d2307dSDag-Erling Smørgrav 
16083d2307dSDag-Erling Smørgrav #include "ssh.h"
16183d2307dSDag-Erling Smørgrav #include "xmalloc.h"
16283d2307dSDag-Erling Smørgrav #include "loginrec.h"
16383d2307dSDag-Erling Smørgrav #include "log.h"
16483d2307dSDag-Erling Smørgrav #include "atomicio.h"
16583d2307dSDag-Erling Smørgrav 
166e73e9afaSDag-Erling Smørgrav RCSID("$Id: loginrec.c,v 1.47 2003/03/10 00:23:07 djm Exp $");
167a9f7d76bSDag-Erling Smørgrav RCSID("$FreeBSD$");
16883d2307dSDag-Erling Smørgrav 
16983d2307dSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
17083d2307dSDag-Erling Smørgrav #  include <util.h>
17183d2307dSDag-Erling Smørgrav #endif
17283d2307dSDag-Erling Smørgrav 
17383d2307dSDag-Erling Smørgrav #ifdef HAVE_LIBUTIL_H
17483d2307dSDag-Erling Smørgrav #   include <libutil.h>
17583d2307dSDag-Erling Smørgrav #endif
17683d2307dSDag-Erling Smørgrav 
17783d2307dSDag-Erling Smørgrav /**
17883d2307dSDag-Erling Smørgrav  ** prototypes for helper functions in this file
17983d2307dSDag-Erling Smørgrav  **/
18083d2307dSDag-Erling Smørgrav 
18183d2307dSDag-Erling Smørgrav #if HAVE_UTMP_H
18283d2307dSDag-Erling Smørgrav void set_utmp_time(struct logininfo *li, struct utmp *ut);
18383d2307dSDag-Erling Smørgrav void construct_utmp(struct logininfo *li, struct utmp *ut);
18483d2307dSDag-Erling Smørgrav #endif
18583d2307dSDag-Erling Smørgrav 
18683d2307dSDag-Erling Smørgrav #ifdef HAVE_UTMPX_H
18783d2307dSDag-Erling Smørgrav void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
18883d2307dSDag-Erling Smørgrav void construct_utmpx(struct logininfo *li, struct utmpx *ut);
18983d2307dSDag-Erling Smørgrav #endif
19083d2307dSDag-Erling Smørgrav 
19183d2307dSDag-Erling Smørgrav int utmp_write_entry(struct logininfo *li);
19283d2307dSDag-Erling Smørgrav int utmpx_write_entry(struct logininfo *li);
19383d2307dSDag-Erling Smørgrav int wtmp_write_entry(struct logininfo *li);
19483d2307dSDag-Erling Smørgrav int wtmpx_write_entry(struct logininfo *li);
19583d2307dSDag-Erling Smørgrav int lastlog_write_entry(struct logininfo *li);
19683d2307dSDag-Erling Smørgrav int syslogin_write_entry(struct logininfo *li);
19783d2307dSDag-Erling Smørgrav 
19883d2307dSDag-Erling Smørgrav int getlast_entry(struct logininfo *li);
19983d2307dSDag-Erling Smørgrav int lastlog_get_entry(struct logininfo *li);
20083d2307dSDag-Erling Smørgrav int wtmp_get_entry(struct logininfo *li);
20183d2307dSDag-Erling Smørgrav int wtmpx_get_entry(struct logininfo *li);
20283d2307dSDag-Erling Smørgrav 
20383d2307dSDag-Erling Smørgrav /* pick the shortest string */
20483d2307dSDag-Erling Smørgrav #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
20583d2307dSDag-Erling Smørgrav 
20683d2307dSDag-Erling Smørgrav /**
20783d2307dSDag-Erling Smørgrav  ** platform-independent login functions
20883d2307dSDag-Erling Smørgrav  **/
20983d2307dSDag-Erling Smørgrav 
21083d2307dSDag-Erling Smørgrav /* login_login(struct logininfo *)     -Record a login
21183d2307dSDag-Erling Smørgrav  *
21283d2307dSDag-Erling Smørgrav  * Call with a pointer to a struct logininfo initialised with
21383d2307dSDag-Erling Smørgrav  * login_init_entry() or login_alloc_entry()
21483d2307dSDag-Erling Smørgrav  *
21583d2307dSDag-Erling Smørgrav  * Returns:
21683d2307dSDag-Erling Smørgrav  *  >0 if successful
21783d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
21883d2307dSDag-Erling Smørgrav  */
21983d2307dSDag-Erling Smørgrav int
22083d2307dSDag-Erling Smørgrav login_login (struct logininfo *li)
22183d2307dSDag-Erling Smørgrav {
22283d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGIN;
22383d2307dSDag-Erling Smørgrav 	return login_write(li);
22483d2307dSDag-Erling Smørgrav }
22583d2307dSDag-Erling Smørgrav 
22683d2307dSDag-Erling Smørgrav 
22783d2307dSDag-Erling Smørgrav /* login_logout(struct logininfo *)     - Record a logout
22883d2307dSDag-Erling Smørgrav  *
22983d2307dSDag-Erling Smørgrav  * Call as with login_login()
23083d2307dSDag-Erling Smørgrav  *
23183d2307dSDag-Erling Smørgrav  * Returns:
23283d2307dSDag-Erling Smørgrav  *  >0 if successful
23383d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
23483d2307dSDag-Erling Smørgrav  */
23583d2307dSDag-Erling Smørgrav int
23683d2307dSDag-Erling Smørgrav login_logout(struct logininfo *li)
23783d2307dSDag-Erling Smørgrav {
23883d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGOUT;
23983d2307dSDag-Erling Smørgrav 	return login_write(li);
24083d2307dSDag-Erling Smørgrav }
24183d2307dSDag-Erling Smørgrav 
24283d2307dSDag-Erling Smørgrav /* login_get_lastlog_time(int)           - Retrieve the last login time
24383d2307dSDag-Erling Smørgrav  *
24483d2307dSDag-Erling Smørgrav  * Retrieve the last login time for the given uid. Will try to use the
24583d2307dSDag-Erling Smørgrav  * system lastlog facilities if they are available, but will fall back
24683d2307dSDag-Erling Smørgrav  * to looking in wtmp/wtmpx if necessary
24783d2307dSDag-Erling Smørgrav  *
24883d2307dSDag-Erling Smørgrav  * Returns:
24983d2307dSDag-Erling Smørgrav  *   0 on failure, or if user has never logged in
25083d2307dSDag-Erling Smørgrav  *   Time in seconds from the epoch if successful
25183d2307dSDag-Erling Smørgrav  *
25283d2307dSDag-Erling Smørgrav  * Useful preprocessor symbols:
25383d2307dSDag-Erling Smørgrav  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
25483d2307dSDag-Erling Smørgrav  *                    info
25583d2307dSDag-Erling Smørgrav  *   USE_LASTLOG: If set, indicates the presence of system lastlog
25683d2307dSDag-Erling Smørgrav  *                facilities. If this and DISABLE_LASTLOG are not set,
25783d2307dSDag-Erling Smørgrav  *                try to retrieve lastlog information from wtmp/wtmpx.
25883d2307dSDag-Erling Smørgrav  */
25983d2307dSDag-Erling Smørgrav unsigned int
26083d2307dSDag-Erling Smørgrav login_get_lastlog_time(const int uid)
26183d2307dSDag-Erling Smørgrav {
26283d2307dSDag-Erling Smørgrav 	struct logininfo li;
26383d2307dSDag-Erling Smørgrav 
26483d2307dSDag-Erling Smørgrav 	if (login_get_lastlog(&li, uid))
26583d2307dSDag-Erling Smørgrav 		return li.tv_sec;
26683d2307dSDag-Erling Smørgrav 	else
26783d2307dSDag-Erling Smørgrav 		return 0;
26883d2307dSDag-Erling Smørgrav }
26983d2307dSDag-Erling Smørgrav 
27083d2307dSDag-Erling Smørgrav /* login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
27183d2307dSDag-Erling Smørgrav  *
27283d2307dSDag-Erling Smørgrav  * Retrieve a logininfo structure populated (only partially) with
27383d2307dSDag-Erling Smørgrav  * information from the system lastlog data, or from wtmp/wtmpx if no
27483d2307dSDag-Erling Smørgrav  * system lastlog information exists.
27583d2307dSDag-Erling Smørgrav  *
27683d2307dSDag-Erling Smørgrav  * Note this routine must be given a pre-allocated logininfo.
27783d2307dSDag-Erling Smørgrav  *
27883d2307dSDag-Erling Smørgrav  * Returns:
27983d2307dSDag-Erling Smørgrav  *  >0: A pointer to your struct logininfo if successful
28083d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
28183d2307dSDag-Erling Smørgrav  *
28283d2307dSDag-Erling Smørgrav  */
28383d2307dSDag-Erling Smørgrav struct logininfo *
28483d2307dSDag-Erling Smørgrav login_get_lastlog(struct logininfo *li, const int uid)
28583d2307dSDag-Erling Smørgrav {
28683d2307dSDag-Erling Smørgrav 	struct passwd *pw;
28783d2307dSDag-Erling Smørgrav 
28883d2307dSDag-Erling Smørgrav 	memset(li, '\0', sizeof(*li));
28983d2307dSDag-Erling Smørgrav 	li->uid = uid;
29083d2307dSDag-Erling Smørgrav 
29183d2307dSDag-Erling Smørgrav 	/*
29283d2307dSDag-Erling Smørgrav 	 * If we don't have a 'real' lastlog, we need the username to
29383d2307dSDag-Erling Smørgrav 	 * reliably search wtmp(x) for the last login (see
29483d2307dSDag-Erling Smørgrav 	 * wtmp_get_entry().)
29583d2307dSDag-Erling Smørgrav 	 */
29683d2307dSDag-Erling Smørgrav 	pw = getpwuid(uid);
29783d2307dSDag-Erling Smørgrav 	if (pw == NULL)
29883d2307dSDag-Erling Smørgrav 		fatal("login_get_lastlog: Cannot find account for uid %i", uid);
29983d2307dSDag-Erling Smørgrav 
30083d2307dSDag-Erling Smørgrav 	/* No MIN_SIZEOF here - we absolutely *must not* truncate the
30183d2307dSDag-Erling Smørgrav 	 * username */
30283d2307dSDag-Erling Smørgrav 	strlcpy(li->username, pw->pw_name, sizeof(li->username));
30383d2307dSDag-Erling Smørgrav 
30483d2307dSDag-Erling Smørgrav 	if (getlast_entry(li))
30583d2307dSDag-Erling Smørgrav 		return li;
30683d2307dSDag-Erling Smørgrav 	else
30783d2307dSDag-Erling Smørgrav 		return NULL;
30883d2307dSDag-Erling Smørgrav }
30983d2307dSDag-Erling Smørgrav 
31083d2307dSDag-Erling Smørgrav 
31183d2307dSDag-Erling Smørgrav /* login_alloc_entry(int, char*, char*, char*)    - Allocate and initialise
31283d2307dSDag-Erling Smørgrav  *                                                  a logininfo structure
31383d2307dSDag-Erling Smørgrav  *
31483d2307dSDag-Erling Smørgrav  * This function creates a new struct logininfo, a data structure
31583d2307dSDag-Erling Smørgrav  * meant to carry the information required to portably record login info.
31683d2307dSDag-Erling Smørgrav  *
31783d2307dSDag-Erling Smørgrav  * Returns a pointer to a newly created struct logininfo. If memory
31883d2307dSDag-Erling Smørgrav  * allocation fails, the program halts.
31983d2307dSDag-Erling Smørgrav  */
32083d2307dSDag-Erling Smørgrav struct
32183d2307dSDag-Erling Smørgrav logininfo *login_alloc_entry(int pid, const char *username,
32283d2307dSDag-Erling Smørgrav 			     const char *hostname, const char *line)
32383d2307dSDag-Erling Smørgrav {
32483d2307dSDag-Erling Smørgrav 	struct logininfo *newli;
32583d2307dSDag-Erling Smørgrav 
32683d2307dSDag-Erling Smørgrav 	newli = (struct logininfo *) xmalloc (sizeof(*newli));
32783d2307dSDag-Erling Smørgrav 	(void)login_init_entry(newli, pid, username, hostname, line);
32883d2307dSDag-Erling Smørgrav 	return newli;
32983d2307dSDag-Erling Smørgrav }
33083d2307dSDag-Erling Smørgrav 
33183d2307dSDag-Erling Smørgrav 
33283d2307dSDag-Erling Smørgrav /* login_free_entry(struct logininfo *)    - free struct memory */
33383d2307dSDag-Erling Smørgrav void
33483d2307dSDag-Erling Smørgrav login_free_entry(struct logininfo *li)
33583d2307dSDag-Erling Smørgrav {
33683d2307dSDag-Erling Smørgrav 	xfree(li);
33783d2307dSDag-Erling Smørgrav }
33883d2307dSDag-Erling Smørgrav 
33983d2307dSDag-Erling Smørgrav 
34083d2307dSDag-Erling Smørgrav /* login_init_entry(struct logininfo *, int, char*, char*, char*)
34183d2307dSDag-Erling Smørgrav  *                                        - initialise a struct logininfo
34283d2307dSDag-Erling Smørgrav  *
34383d2307dSDag-Erling Smørgrav  * Populates a new struct logininfo, a data structure meant to carry
34483d2307dSDag-Erling Smørgrav  * the information required to portably record login info.
34583d2307dSDag-Erling Smørgrav  *
34683d2307dSDag-Erling Smørgrav  * Returns: 1
34783d2307dSDag-Erling Smørgrav  */
34883d2307dSDag-Erling Smørgrav int
34983d2307dSDag-Erling Smørgrav login_init_entry(struct logininfo *li, int pid, const char *username,
35083d2307dSDag-Erling Smørgrav 		 const char *hostname, const char *line)
35183d2307dSDag-Erling Smørgrav {
35283d2307dSDag-Erling Smørgrav 	struct passwd *pw;
35383d2307dSDag-Erling Smørgrav 
35483d2307dSDag-Erling Smørgrav 	memset(li, 0, sizeof(*li));
35583d2307dSDag-Erling Smørgrav 
35683d2307dSDag-Erling Smørgrav 	li->pid = pid;
35783d2307dSDag-Erling Smørgrav 
35883d2307dSDag-Erling Smørgrav 	/* set the line information */
35983d2307dSDag-Erling Smørgrav 	if (line)
36083d2307dSDag-Erling Smørgrav 		line_fullname(li->line, line, sizeof(li->line));
36183d2307dSDag-Erling Smørgrav 
36283d2307dSDag-Erling Smørgrav 	if (username) {
36383d2307dSDag-Erling Smørgrav 		strlcpy(li->username, username, sizeof(li->username));
36483d2307dSDag-Erling Smørgrav 		pw = getpwnam(li->username);
36583d2307dSDag-Erling Smørgrav 		if (pw == NULL)
36683d2307dSDag-Erling Smørgrav 			fatal("login_init_entry: Cannot find user \"%s\"", li->username);
36783d2307dSDag-Erling Smørgrav 		li->uid = pw->pw_uid;
36883d2307dSDag-Erling Smørgrav 	}
36983d2307dSDag-Erling Smørgrav 
37083d2307dSDag-Erling Smørgrav 	if (hostname)
37183d2307dSDag-Erling Smørgrav 		strlcpy(li->hostname, hostname, sizeof(li->hostname));
37283d2307dSDag-Erling Smørgrav 
37383d2307dSDag-Erling Smørgrav 	return 1;
37483d2307dSDag-Erling Smørgrav }
37583d2307dSDag-Erling Smørgrav 
37683d2307dSDag-Erling Smørgrav /* login_set_current_time(struct logininfo *)    - set the current time
37783d2307dSDag-Erling Smørgrav  *
37883d2307dSDag-Erling Smørgrav  * Set the current time in a logininfo structure. This function is
37983d2307dSDag-Erling Smørgrav  * meant to eliminate the need to deal with system dependencies for
38083d2307dSDag-Erling Smørgrav  * time handling.
38183d2307dSDag-Erling Smørgrav  */
38283d2307dSDag-Erling Smørgrav void
38383d2307dSDag-Erling Smørgrav login_set_current_time(struct logininfo *li)
38483d2307dSDag-Erling Smørgrav {
38583d2307dSDag-Erling Smørgrav 	struct timeval tv;
38683d2307dSDag-Erling Smørgrav 
38783d2307dSDag-Erling Smørgrav 	gettimeofday(&tv, NULL);
38883d2307dSDag-Erling Smørgrav 
38983d2307dSDag-Erling Smørgrav 	li->tv_sec = tv.tv_sec;
39083d2307dSDag-Erling Smørgrav 	li->tv_usec = tv.tv_usec;
39183d2307dSDag-Erling Smørgrav }
39283d2307dSDag-Erling Smørgrav 
39383d2307dSDag-Erling Smørgrav /* copy a sockaddr_* into our logininfo */
39483d2307dSDag-Erling Smørgrav void
39583d2307dSDag-Erling Smørgrav login_set_addr(struct logininfo *li, const struct sockaddr *sa,
39683d2307dSDag-Erling Smørgrav 	       const unsigned int sa_size)
39783d2307dSDag-Erling Smørgrav {
39883d2307dSDag-Erling Smørgrav 	unsigned int bufsize = sa_size;
39983d2307dSDag-Erling Smørgrav 
40083d2307dSDag-Erling Smørgrav 	/* make sure we don't overrun our union */
40183d2307dSDag-Erling Smørgrav 	if (sizeof(li->hostaddr) < sa_size)
40283d2307dSDag-Erling Smørgrav 		bufsize = sizeof(li->hostaddr);
40383d2307dSDag-Erling Smørgrav 
40483d2307dSDag-Erling Smørgrav 	memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
40583d2307dSDag-Erling Smørgrav }
40683d2307dSDag-Erling Smørgrav 
40783d2307dSDag-Erling Smørgrav 
40883d2307dSDag-Erling Smørgrav /**
40983d2307dSDag-Erling Smørgrav  ** login_write: Call low-level recording functions based on autoconf
41083d2307dSDag-Erling Smørgrav  ** results
41183d2307dSDag-Erling Smørgrav  **/
41283d2307dSDag-Erling Smørgrav int
41383d2307dSDag-Erling Smørgrav login_write (struct logininfo *li)
41483d2307dSDag-Erling Smørgrav {
41583d2307dSDag-Erling Smørgrav #ifndef HAVE_CYGWIN
41683d2307dSDag-Erling Smørgrav 	if ((int)geteuid() != 0) {
41783d2307dSDag-Erling Smørgrav 	  log("Attempt to write login records by non-root user (aborting)");
41883d2307dSDag-Erling Smørgrav 	  return 1;
41983d2307dSDag-Erling Smørgrav 	}
42083d2307dSDag-Erling Smørgrav #endif
42183d2307dSDag-Erling Smørgrav 
42283d2307dSDag-Erling Smørgrav 	/* set the timestamp */
42383d2307dSDag-Erling Smørgrav 	login_set_current_time(li);
42483d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN
42583d2307dSDag-Erling Smørgrav 	syslogin_write_entry(li);
42683d2307dSDag-Erling Smørgrav #endif
42783d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
42883d2307dSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGIN) {
42983d2307dSDag-Erling Smørgrav 		lastlog_write_entry(li);
43083d2307dSDag-Erling Smørgrav 	}
43183d2307dSDag-Erling Smørgrav #endif
43283d2307dSDag-Erling Smørgrav #ifdef USE_UTMP
43383d2307dSDag-Erling Smørgrav 	utmp_write_entry(li);
43483d2307dSDag-Erling Smørgrav #endif
43583d2307dSDag-Erling Smørgrav #ifdef USE_WTMP
43683d2307dSDag-Erling Smørgrav 	wtmp_write_entry(li);
43783d2307dSDag-Erling Smørgrav #endif
43883d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX
43983d2307dSDag-Erling Smørgrav 	utmpx_write_entry(li);
44083d2307dSDag-Erling Smørgrav #endif
44183d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX
44283d2307dSDag-Erling Smørgrav 	wtmpx_write_entry(li);
44383d2307dSDag-Erling Smørgrav #endif
44483d2307dSDag-Erling Smørgrav 	return 0;
44583d2307dSDag-Erling Smørgrav }
44683d2307dSDag-Erling Smørgrav 
44783d2307dSDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
44883d2307dSDag-Erling Smørgrav int
44983d2307dSDag-Erling Smørgrav login_utmp_only(struct logininfo *li)
45083d2307dSDag-Erling Smørgrav {
45183d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGIN;
45283d2307dSDag-Erling Smørgrav 	login_set_current_time(li);
45383d2307dSDag-Erling Smørgrav # ifdef USE_UTMP
45483d2307dSDag-Erling Smørgrav 	utmp_write_entry(li);
45583d2307dSDag-Erling Smørgrav # endif
45683d2307dSDag-Erling Smørgrav # ifdef USE_WTMP
45783d2307dSDag-Erling Smørgrav 	wtmp_write_entry(li);
45883d2307dSDag-Erling Smørgrav # endif
45983d2307dSDag-Erling Smørgrav # ifdef USE_UTMPX
46083d2307dSDag-Erling Smørgrav 	utmpx_write_entry(li);
46183d2307dSDag-Erling Smørgrav # endif
46283d2307dSDag-Erling Smørgrav # ifdef USE_WTMPX
46383d2307dSDag-Erling Smørgrav 	wtmpx_write_entry(li);
46483d2307dSDag-Erling Smørgrav # endif
46583d2307dSDag-Erling Smørgrav 	return 0;
46683d2307dSDag-Erling Smørgrav }
46783d2307dSDag-Erling Smørgrav #endif
46883d2307dSDag-Erling Smørgrav 
46983d2307dSDag-Erling Smørgrav /**
47083d2307dSDag-Erling Smørgrav  ** getlast_entry: Call low-level functions to retrieve the last login
47183d2307dSDag-Erling Smørgrav  **                time.
47283d2307dSDag-Erling Smørgrav  **/
47383d2307dSDag-Erling Smørgrav 
47483d2307dSDag-Erling Smørgrav /* take the uid in li and return the last login time */
47583d2307dSDag-Erling Smørgrav int
47683d2307dSDag-Erling Smørgrav getlast_entry(struct logininfo *li)
47783d2307dSDag-Erling Smørgrav {
47883d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
47983d2307dSDag-Erling Smørgrav 	return(lastlog_get_entry(li));
48083d2307dSDag-Erling Smørgrav #else /* !USE_LASTLOG */
48183d2307dSDag-Erling Smørgrav 
48283d2307dSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
48383d2307dSDag-Erling Smørgrav 	/* On some systems we shouldn't even try to obtain last login
48483d2307dSDag-Erling Smørgrav 	 * time, e.g. AIX */
48583d2307dSDag-Erling Smørgrav 	return 0;
48683d2307dSDag-Erling Smørgrav # else /* DISABLE_LASTLOG */
48783d2307dSDag-Erling Smørgrav 	/* Try to retrieve the last login time from wtmp */
48883d2307dSDag-Erling Smørgrav #  if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
48983d2307dSDag-Erling Smørgrav 	/* retrieve last login time from utmp */
49083d2307dSDag-Erling Smørgrav 	return (wtmp_get_entry(li));
49183d2307dSDag-Erling Smørgrav #  else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
49283d2307dSDag-Erling Smørgrav 	/* If wtmp isn't available, try wtmpx */
49383d2307dSDag-Erling Smørgrav #   if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
49483d2307dSDag-Erling Smørgrav 	/* retrieve last login time from utmpx */
49583d2307dSDag-Erling Smørgrav 	return (wtmpx_get_entry(li));
49683d2307dSDag-Erling Smørgrav #   else
49783d2307dSDag-Erling Smørgrav 	/* Give up: No means of retrieving last login time */
49883d2307dSDag-Erling Smørgrav 	return 0;
49983d2307dSDag-Erling Smørgrav #   endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
50083d2307dSDag-Erling Smørgrav #  endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
50183d2307dSDag-Erling Smørgrav # endif /* DISABLE_LASTLOG */
50283d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */
50383d2307dSDag-Erling Smørgrav }
50483d2307dSDag-Erling Smørgrav 
50583d2307dSDag-Erling Smørgrav 
50683d2307dSDag-Erling Smørgrav 
50783d2307dSDag-Erling Smørgrav /*
50883d2307dSDag-Erling Smørgrav  * 'line' string utility functions
50983d2307dSDag-Erling Smørgrav  *
51083d2307dSDag-Erling Smørgrav  * These functions process the 'line' string into one of three forms:
51183d2307dSDag-Erling Smørgrav  *
51283d2307dSDag-Erling Smørgrav  * 1. The full filename (including '/dev')
51383d2307dSDag-Erling Smørgrav  * 2. The stripped name (excluding '/dev')
51483d2307dSDag-Erling Smørgrav  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
51583d2307dSDag-Erling Smørgrav  *                               /dev/pts/1  -> ts/1 )
51683d2307dSDag-Erling Smørgrav  *
51783d2307dSDag-Erling Smørgrav  * Form 3 is used on some systems to identify a .tmp.? entry when
51883d2307dSDag-Erling Smørgrav  * attempting to remove it. Typically both addition and removal is
51983d2307dSDag-Erling Smørgrav  * performed by one application - say, sshd - so as long as the choice
52083d2307dSDag-Erling Smørgrav  * uniquely identifies a terminal it's ok.
52183d2307dSDag-Erling Smørgrav  */
52283d2307dSDag-Erling Smørgrav 
52383d2307dSDag-Erling Smørgrav 
52483d2307dSDag-Erling Smørgrav /* line_fullname(): add the leading '/dev/' if it doesn't exist make
52583d2307dSDag-Erling Smørgrav  * sure dst has enough space, if not just copy src (ugh) */
52683d2307dSDag-Erling Smørgrav char *
52783d2307dSDag-Erling Smørgrav line_fullname(char *dst, const char *src, int dstsize)
52883d2307dSDag-Erling Smørgrav {
52983d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
53083d2307dSDag-Erling Smørgrav 	if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) {
53183d2307dSDag-Erling Smørgrav 		strlcpy(dst, src, dstsize);
53283d2307dSDag-Erling Smørgrav 	} else {
53383d2307dSDag-Erling Smørgrav 		strlcpy(dst, "/dev/", dstsize);
53483d2307dSDag-Erling Smørgrav 		strlcat(dst, src, dstsize);
53583d2307dSDag-Erling Smørgrav 	}
53683d2307dSDag-Erling Smørgrav 	return dst;
53783d2307dSDag-Erling Smørgrav }
53883d2307dSDag-Erling Smørgrav 
53983d2307dSDag-Erling Smørgrav /* line_stripname(): strip the leading '/dev' if it exists, return dst */
54083d2307dSDag-Erling Smørgrav char *
54183d2307dSDag-Erling Smørgrav line_stripname(char *dst, const char *src, int dstsize)
54283d2307dSDag-Erling Smørgrav {
54383d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
54483d2307dSDag-Erling Smørgrav 	if (strncmp(src, "/dev/", 5) == 0)
54583d2307dSDag-Erling Smørgrav 		strlcpy(dst, src + 5, dstsize);
54683d2307dSDag-Erling Smørgrav 	else
54783d2307dSDag-Erling Smørgrav 		strlcpy(dst, src, dstsize);
54883d2307dSDag-Erling Smørgrav 	return dst;
54983d2307dSDag-Erling Smørgrav }
55083d2307dSDag-Erling Smørgrav 
55183d2307dSDag-Erling Smørgrav /* line_abbrevname(): Return the abbreviated (usually four-character)
55283d2307dSDag-Erling Smørgrav  * form of the line (Just use the last <dstsize> characters of the
55383d2307dSDag-Erling Smørgrav  * full name.)
55483d2307dSDag-Erling Smørgrav  *
55583d2307dSDag-Erling Smørgrav  * NOTE: use strncpy because we do NOT necessarily want zero
55683d2307dSDag-Erling Smørgrav  * termination */
55783d2307dSDag-Erling Smørgrav char *
55883d2307dSDag-Erling Smørgrav line_abbrevname(char *dst, const char *src, int dstsize)
55983d2307dSDag-Erling Smørgrav {
56083d2307dSDag-Erling Smørgrav 	size_t len;
56183d2307dSDag-Erling Smørgrav 
56283d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
56383d2307dSDag-Erling Smørgrav 
56483d2307dSDag-Erling Smørgrav 	/* Always skip prefix if present */
56583d2307dSDag-Erling Smørgrav 	if (strncmp(src, "/dev/", 5) == 0)
56683d2307dSDag-Erling Smørgrav 		src += 5;
56783d2307dSDag-Erling Smørgrav 
56883d2307dSDag-Erling Smørgrav #ifdef WITH_ABBREV_NO_TTY
56983d2307dSDag-Erling Smørgrav 	if (strncmp(src, "tty", 3) == 0)
57083d2307dSDag-Erling Smørgrav 		src += 3;
57183d2307dSDag-Erling Smørgrav #endif
57283d2307dSDag-Erling Smørgrav 
57383d2307dSDag-Erling Smørgrav 	len = strlen(src);
57483d2307dSDag-Erling Smørgrav 
57583d2307dSDag-Erling Smørgrav 	if (len > 0) {
57683d2307dSDag-Erling Smørgrav 		if (((int)len - dstsize) > 0)
57783d2307dSDag-Erling Smørgrav 			src +=  ((int)len - dstsize);
57883d2307dSDag-Erling Smørgrav 
57983d2307dSDag-Erling Smørgrav 		/* note: _don't_ change this to strlcpy */
58083d2307dSDag-Erling Smørgrav 		strncpy(dst, src, (size_t)dstsize);
58183d2307dSDag-Erling Smørgrav 	}
58283d2307dSDag-Erling Smørgrav 
58383d2307dSDag-Erling Smørgrav 	return dst;
58483d2307dSDag-Erling Smørgrav }
58583d2307dSDag-Erling Smørgrav 
58683d2307dSDag-Erling Smørgrav /**
58783d2307dSDag-Erling Smørgrav  ** utmp utility functions
58883d2307dSDag-Erling Smørgrav  **
58983d2307dSDag-Erling Smørgrav  ** These functions manipulate struct utmp, taking system differences
59083d2307dSDag-Erling Smørgrav  ** into account.
59183d2307dSDag-Erling Smørgrav  **/
59283d2307dSDag-Erling Smørgrav 
59383d2307dSDag-Erling Smørgrav #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
59483d2307dSDag-Erling Smørgrav 
59583d2307dSDag-Erling Smørgrav /* build the utmp structure */
59683d2307dSDag-Erling Smørgrav void
59783d2307dSDag-Erling Smørgrav set_utmp_time(struct logininfo *li, struct utmp *ut)
59883d2307dSDag-Erling Smørgrav {
59983d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMP
60083d2307dSDag-Erling Smørgrav 	ut->ut_tv.tv_sec = li->tv_sec;
60183d2307dSDag-Erling Smørgrav 	ut->ut_tv.tv_usec = li->tv_usec;
60283d2307dSDag-Erling Smørgrav # else
60383d2307dSDag-Erling Smørgrav #  ifdef HAVE_TIME_IN_UTMP
60483d2307dSDag-Erling Smørgrav 	ut->ut_time = li->tv_sec;
60583d2307dSDag-Erling Smørgrav #  endif
60683d2307dSDag-Erling Smørgrav # endif
60783d2307dSDag-Erling Smørgrav }
60883d2307dSDag-Erling Smørgrav 
60983d2307dSDag-Erling Smørgrav void
61083d2307dSDag-Erling Smørgrav construct_utmp(struct logininfo *li,
61183d2307dSDag-Erling Smørgrav 		    struct utmp *ut)
61283d2307dSDag-Erling Smørgrav {
613e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
614e73e9afaSDag-Erling Smørgrav 	struct sockaddr_in6 *sa6;
615e73e9afaSDag-Erling Smørgrav #  endif
61683d2307dSDag-Erling Smørgrav 	memset(ut, '\0', sizeof(*ut));
61783d2307dSDag-Erling Smørgrav 
61883d2307dSDag-Erling Smørgrav 	/* First fill out fields used for both logins and logouts */
61983d2307dSDag-Erling Smørgrav 
62083d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMP
62183d2307dSDag-Erling Smørgrav 	line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
62283d2307dSDag-Erling Smørgrav # endif
62383d2307dSDag-Erling Smørgrav 
62483d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP
62583d2307dSDag-Erling Smørgrav 	/* This is done here to keep utmp constants out of struct logininfo */
62683d2307dSDag-Erling Smørgrav 	switch (li->type) {
62783d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
62883d2307dSDag-Erling Smørgrav 		ut->ut_type = USER_PROCESS;
629f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
63083d2307dSDag-Erling Smørgrav 		cray_set_tmpdir(ut);
63183d2307dSDag-Erling Smørgrav #endif
63283d2307dSDag-Erling Smørgrav 		break;
63383d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
63483d2307dSDag-Erling Smørgrav 		ut->ut_type = DEAD_PROCESS;
635f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
63683d2307dSDag-Erling Smørgrav 		cray_retain_utmp(ut, li->pid);
63783d2307dSDag-Erling Smørgrav #endif
63883d2307dSDag-Erling Smørgrav 		break;
63983d2307dSDag-Erling Smørgrav 	}
64083d2307dSDag-Erling Smørgrav # endif
64183d2307dSDag-Erling Smørgrav 	set_utmp_time(li, ut);
64283d2307dSDag-Erling Smørgrav 
64383d2307dSDag-Erling Smørgrav 	line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
64483d2307dSDag-Erling Smørgrav 
64583d2307dSDag-Erling Smørgrav # ifdef HAVE_PID_IN_UTMP
64683d2307dSDag-Erling Smørgrav 	ut->ut_pid = li->pid;
64783d2307dSDag-Erling Smørgrav # endif
64883d2307dSDag-Erling Smørgrav 
64983d2307dSDag-Erling Smørgrav 	/* If we're logging out, leave all other fields blank */
65083d2307dSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGOUT)
65183d2307dSDag-Erling Smørgrav 	  return;
65283d2307dSDag-Erling Smørgrav 
65383d2307dSDag-Erling Smørgrav 	/*
65483d2307dSDag-Erling Smørgrav 	 * These fields are only used when logging in, and are blank
65583d2307dSDag-Erling Smørgrav 	 * for logouts.
65683d2307dSDag-Erling Smørgrav 	 */
65783d2307dSDag-Erling Smørgrav 
65883d2307dSDag-Erling Smørgrav 	/* Use strncpy because we don't necessarily want null termination */
65983d2307dSDag-Erling Smørgrav 	strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
66083d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP
661a9f7d76bSDag-Erling Smørgrav 	realhostname_sa(ut->ut_host, sizeof ut->ut_host,
662a9f7d76bSDag-Erling Smørgrav 	    &li->hostaddr.sa, li->hostaddr.sa.sa_len);
66383d2307dSDag-Erling Smørgrav # endif
66483d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMP
66583d2307dSDag-Erling Smørgrav 	/* this is just a 32-bit IP address */
66683d2307dSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET)
66783d2307dSDag-Erling Smørgrav 		ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
66883d2307dSDag-Erling Smørgrav # endif
669e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
670e73e9afaSDag-Erling Smørgrav 	/* this is just a 128-bit IPv6 address */
671e73e9afaSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET6) {
672e73e9afaSDag-Erling Smørgrav 		sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
673e73e9afaSDag-Erling Smørgrav 		memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
674e73e9afaSDag-Erling Smørgrav 		if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
675e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
676e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[1] = 0;
677e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[2] = 0;
678e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[3] = 0;
679e73e9afaSDag-Erling Smørgrav 		}
680e73e9afaSDag-Erling Smørgrav 	}
681e73e9afaSDag-Erling Smørgrav # endif
68283d2307dSDag-Erling Smørgrav }
68383d2307dSDag-Erling Smørgrav #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
68483d2307dSDag-Erling Smørgrav 
68583d2307dSDag-Erling Smørgrav /**
68683d2307dSDag-Erling Smørgrav  ** utmpx utility functions
68783d2307dSDag-Erling Smørgrav  **
68883d2307dSDag-Erling Smørgrav  ** These functions manipulate struct utmpx, accounting for system
68983d2307dSDag-Erling Smørgrav  ** variations.
69083d2307dSDag-Erling Smørgrav  **/
69183d2307dSDag-Erling Smørgrav 
69283d2307dSDag-Erling Smørgrav #if defined(USE_UTMPX) || defined (USE_WTMPX)
69383d2307dSDag-Erling Smørgrav /* build the utmpx structure */
69483d2307dSDag-Erling Smørgrav void
69583d2307dSDag-Erling Smørgrav set_utmpx_time(struct logininfo *li, struct utmpx *utx)
69683d2307dSDag-Erling Smørgrav {
69783d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMPX
69883d2307dSDag-Erling Smørgrav 	utx->ut_tv.tv_sec = li->tv_sec;
69983d2307dSDag-Erling Smørgrav 	utx->ut_tv.tv_usec = li->tv_usec;
70083d2307dSDag-Erling Smørgrav # else /* HAVE_TV_IN_UTMPX */
70183d2307dSDag-Erling Smørgrav #  ifdef HAVE_TIME_IN_UTMPX
70283d2307dSDag-Erling Smørgrav 	utx->ut_time = li->tv_sec;
70383d2307dSDag-Erling Smørgrav #  endif /* HAVE_TIME_IN_UTMPX */
70483d2307dSDag-Erling Smørgrav # endif /* HAVE_TV_IN_UTMPX */
70583d2307dSDag-Erling Smørgrav }
70683d2307dSDag-Erling Smørgrav 
70783d2307dSDag-Erling Smørgrav void
70883d2307dSDag-Erling Smørgrav construct_utmpx(struct logininfo *li, struct utmpx *utx)
70983d2307dSDag-Erling Smørgrav {
710e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
711e73e9afaSDag-Erling Smørgrav 	struct sockaddr_in6 *sa6;
712e73e9afaSDag-Erling Smørgrav #  endif
71383d2307dSDag-Erling Smørgrav 	memset(utx, '\0', sizeof(*utx));
71483d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX
71583d2307dSDag-Erling Smørgrav 	line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
71683d2307dSDag-Erling Smørgrav # endif
71783d2307dSDag-Erling Smørgrav 
71883d2307dSDag-Erling Smørgrav 	/* this is done here to keep utmp constants out of loginrec.h */
71983d2307dSDag-Erling Smørgrav 	switch (li->type) {
72083d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
72183d2307dSDag-Erling Smørgrav 		utx->ut_type = USER_PROCESS;
72283d2307dSDag-Erling Smørgrav 		break;
72383d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
72483d2307dSDag-Erling Smørgrav 		utx->ut_type = DEAD_PROCESS;
72583d2307dSDag-Erling Smørgrav 		break;
72683d2307dSDag-Erling Smørgrav 	}
72783d2307dSDag-Erling Smørgrav 	line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
72883d2307dSDag-Erling Smørgrav 	set_utmpx_time(li, utx);
72983d2307dSDag-Erling Smørgrav 	utx->ut_pid = li->pid;
73083d2307dSDag-Erling Smørgrav 	/* strncpy(): Don't necessarily want null termination */
73183d2307dSDag-Erling Smørgrav 	strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
73283d2307dSDag-Erling Smørgrav 
73383d2307dSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGOUT)
73483d2307dSDag-Erling Smørgrav 		return;
73583d2307dSDag-Erling Smørgrav 
73683d2307dSDag-Erling Smørgrav 	/*
73783d2307dSDag-Erling Smørgrav 	 * These fields are only used when logging in, and are blank
73883d2307dSDag-Erling Smørgrav 	 * for logouts.
73983d2307dSDag-Erling Smørgrav 	 */
74083d2307dSDag-Erling Smørgrav 
74183d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX
74283d2307dSDag-Erling Smørgrav 	strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
74383d2307dSDag-Erling Smørgrav # endif
74483d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMPX
74583d2307dSDag-Erling Smørgrav 	/* this is just a 32-bit IP address */
74683d2307dSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET)
74783d2307dSDag-Erling Smørgrav 		utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
74883d2307dSDag-Erling Smørgrav # endif
749e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
750e73e9afaSDag-Erling Smørgrav 	/* this is just a 128-bit IPv6 address */
751e73e9afaSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET6) {
752e73e9afaSDag-Erling Smørgrav 		sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
753e73e9afaSDag-Erling Smørgrav 		memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
754e73e9afaSDag-Erling Smørgrav 		if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
755e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
756e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[1] = 0;
757e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[2] = 0;
758e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[3] = 0;
759e73e9afaSDag-Erling Smørgrav 		}
760e73e9afaSDag-Erling Smørgrav 	}
761e73e9afaSDag-Erling Smørgrav # endif
76283d2307dSDag-Erling Smørgrav # ifdef HAVE_SYSLEN_IN_UTMPX
76383d2307dSDag-Erling Smørgrav 	/* ut_syslen is the length of the utx_host string */
76483d2307dSDag-Erling Smørgrav 	utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
76583d2307dSDag-Erling Smørgrav # endif
76683d2307dSDag-Erling Smørgrav }
76783d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX || USE_WTMPX */
76883d2307dSDag-Erling Smørgrav 
76983d2307dSDag-Erling Smørgrav /**
77083d2307dSDag-Erling Smørgrav  ** Low-level utmp functions
77183d2307dSDag-Erling Smørgrav  **/
77283d2307dSDag-Erling Smørgrav 
77383d2307dSDag-Erling Smørgrav /* FIXME: (ATL) utmp_write_direct needs testing */
77483d2307dSDag-Erling Smørgrav #ifdef USE_UTMP
77583d2307dSDag-Erling Smørgrav 
77683d2307dSDag-Erling Smørgrav /* if we can, use pututline() etc. */
77783d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
77883d2307dSDag-Erling Smørgrav 	defined(HAVE_PUTUTLINE)
77983d2307dSDag-Erling Smørgrav #  define UTMP_USE_LIBRARY
78083d2307dSDag-Erling Smørgrav # endif
78183d2307dSDag-Erling Smørgrav 
78283d2307dSDag-Erling Smørgrav 
78383d2307dSDag-Erling Smørgrav /* write a utmp entry with the system's help (pututline() and pals) */
78483d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
78583d2307dSDag-Erling Smørgrav static int
78683d2307dSDag-Erling Smørgrav utmp_write_library(struct logininfo *li, struct utmp *ut)
78783d2307dSDag-Erling Smørgrav {
78883d2307dSDag-Erling Smørgrav 	setutent();
78983d2307dSDag-Erling Smørgrav 	pututline(ut);
79083d2307dSDag-Erling Smørgrav 
79183d2307dSDag-Erling Smørgrav #  ifdef HAVE_ENDUTENT
79283d2307dSDag-Erling Smørgrav 	endutent();
79383d2307dSDag-Erling Smørgrav #  endif
79483d2307dSDag-Erling Smørgrav 	return 1;
79583d2307dSDag-Erling Smørgrav }
79683d2307dSDag-Erling Smørgrav # else /* UTMP_USE_LIBRARY */
79783d2307dSDag-Erling Smørgrav 
79883d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */
79983d2307dSDag-Erling Smørgrav /* This is a slightly modification of code in OpenBSD's login.c */
80083d2307dSDag-Erling Smørgrav static int
80183d2307dSDag-Erling Smørgrav utmp_write_direct(struct logininfo *li, struct utmp *ut)
80283d2307dSDag-Erling Smørgrav {
80383d2307dSDag-Erling Smørgrav 	struct utmp old_ut;
80483d2307dSDag-Erling Smørgrav 	register int fd;
80583d2307dSDag-Erling Smørgrav 	int tty;
80683d2307dSDag-Erling Smørgrav 
80783d2307dSDag-Erling Smørgrav 	/* FIXME: (ATL) ttyslot() needs local implementation */
80883d2307dSDag-Erling Smørgrav 
80983d2307dSDag-Erling Smørgrav #if defined(HAVE_GETTTYENT)
81083d2307dSDag-Erling Smørgrav 	register struct ttyent *ty;
81183d2307dSDag-Erling Smørgrav 
81283d2307dSDag-Erling Smørgrav 	tty=0;
81383d2307dSDag-Erling Smørgrav 
81483d2307dSDag-Erling Smørgrav 	setttyent();
81583d2307dSDag-Erling Smørgrav 	while ((struct ttyent *)0 != (ty = getttyent())) {
81683d2307dSDag-Erling Smørgrav 		tty++;
81783d2307dSDag-Erling Smørgrav 		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
81883d2307dSDag-Erling Smørgrav 			break;
81983d2307dSDag-Erling Smørgrav 	}
82083d2307dSDag-Erling Smørgrav 	endttyent();
82183d2307dSDag-Erling Smørgrav 
82283d2307dSDag-Erling Smørgrav 	if((struct ttyent *)0 == ty) {
82383d2307dSDag-Erling Smørgrav 		log("utmp_write_entry: tty not found");
82483d2307dSDag-Erling Smørgrav 		return(1);
82583d2307dSDag-Erling Smørgrav 	}
82683d2307dSDag-Erling Smørgrav #else /* FIXME */
82783d2307dSDag-Erling Smørgrav 
82883d2307dSDag-Erling Smørgrav 	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
82983d2307dSDag-Erling Smørgrav 
83083d2307dSDag-Erling Smørgrav #endif /* HAVE_GETTTYENT */
83183d2307dSDag-Erling Smørgrav 
83283d2307dSDag-Erling Smørgrav 	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
83383d2307dSDag-Erling Smørgrav 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
83483d2307dSDag-Erling Smørgrav 		/*
83583d2307dSDag-Erling Smørgrav 		 * Prevent luser from zero'ing out ut_host.
83683d2307dSDag-Erling Smørgrav 		 * If the new ut_line is empty but the old one is not
83783d2307dSDag-Erling Smørgrav 		 * and ut_line and ut_name match, preserve the old ut_line.
83883d2307dSDag-Erling Smørgrav 		 */
83983d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
84083d2307dSDag-Erling Smørgrav 			(ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
84183d2307dSDag-Erling Smørgrav 			(strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
84283d2307dSDag-Erling Smørgrav 			(strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
84383d2307dSDag-Erling Smørgrav 			(void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
84483d2307dSDag-Erling Smørgrav 		}
84583d2307dSDag-Erling Smørgrav 
84683d2307dSDag-Erling Smørgrav 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
84783d2307dSDag-Erling Smørgrav 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
84883d2307dSDag-Erling Smørgrav 			log("utmp_write_direct: error writing %s: %s",
84983d2307dSDag-Erling Smørgrav 			    UTMP_FILE, strerror(errno));
85083d2307dSDag-Erling Smørgrav 
85183d2307dSDag-Erling Smørgrav 		(void)close(fd);
85283d2307dSDag-Erling Smørgrav 		return 1;
85383d2307dSDag-Erling Smørgrav 	} else {
85483d2307dSDag-Erling Smørgrav 		return 0;
85583d2307dSDag-Erling Smørgrav 	}
85683d2307dSDag-Erling Smørgrav }
85783d2307dSDag-Erling Smørgrav # endif /* UTMP_USE_LIBRARY */
85883d2307dSDag-Erling Smørgrav 
85983d2307dSDag-Erling Smørgrav static int
86083d2307dSDag-Erling Smørgrav utmp_perform_login(struct logininfo *li)
86183d2307dSDag-Erling Smørgrav {
86283d2307dSDag-Erling Smørgrav 	struct utmp ut;
86383d2307dSDag-Erling Smørgrav 
86483d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
86583d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
86683d2307dSDag-Erling Smørgrav 	if (!utmp_write_library(li, &ut)) {
86783d2307dSDag-Erling Smørgrav 		log("utmp_perform_login: utmp_write_library() failed");
86883d2307dSDag-Erling Smørgrav 		return 0;
86983d2307dSDag-Erling Smørgrav 	}
87083d2307dSDag-Erling Smørgrav # else
87183d2307dSDag-Erling Smørgrav 	if (!utmp_write_direct(li, &ut)) {
87283d2307dSDag-Erling Smørgrav 		log("utmp_perform_login: utmp_write_direct() failed");
87383d2307dSDag-Erling Smørgrav 		return 0;
87483d2307dSDag-Erling Smørgrav 	}
87583d2307dSDag-Erling Smørgrav # endif
87683d2307dSDag-Erling Smørgrav 	return 1;
87783d2307dSDag-Erling Smørgrav }
87883d2307dSDag-Erling Smørgrav 
87983d2307dSDag-Erling Smørgrav 
88083d2307dSDag-Erling Smørgrav static int
88183d2307dSDag-Erling Smørgrav utmp_perform_logout(struct logininfo *li)
88283d2307dSDag-Erling Smørgrav {
88383d2307dSDag-Erling Smørgrav 	struct utmp ut;
88483d2307dSDag-Erling Smørgrav 
88583d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
88683d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
88783d2307dSDag-Erling Smørgrav 	if (!utmp_write_library(li, &ut)) {
88883d2307dSDag-Erling Smørgrav 		log("utmp_perform_logout: utmp_write_library() failed");
88983d2307dSDag-Erling Smørgrav 		return 0;
89083d2307dSDag-Erling Smørgrav 	}
89183d2307dSDag-Erling Smørgrav # else
89283d2307dSDag-Erling Smørgrav 	if (!utmp_write_direct(li, &ut)) {
89383d2307dSDag-Erling Smørgrav 		log("utmp_perform_logout: utmp_write_direct() failed");
89483d2307dSDag-Erling Smørgrav 		return 0;
89583d2307dSDag-Erling Smørgrav 	}
89683d2307dSDag-Erling Smørgrav # endif
89783d2307dSDag-Erling Smørgrav 	return 1;
89883d2307dSDag-Erling Smørgrav }
89983d2307dSDag-Erling Smørgrav 
90083d2307dSDag-Erling Smørgrav 
90183d2307dSDag-Erling Smørgrav int
90283d2307dSDag-Erling Smørgrav utmp_write_entry(struct logininfo *li)
90383d2307dSDag-Erling Smørgrav {
90483d2307dSDag-Erling Smørgrav 	switch(li->type) {
90583d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
90683d2307dSDag-Erling Smørgrav 		return utmp_perform_login(li);
90783d2307dSDag-Erling Smørgrav 
90883d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
90983d2307dSDag-Erling Smørgrav 		return utmp_perform_logout(li);
91083d2307dSDag-Erling Smørgrav 
91183d2307dSDag-Erling Smørgrav 	default:
91283d2307dSDag-Erling Smørgrav 		log("utmp_write_entry: invalid type field");
91383d2307dSDag-Erling Smørgrav 		return 0;
91483d2307dSDag-Erling Smørgrav 	}
91583d2307dSDag-Erling Smørgrav }
91683d2307dSDag-Erling Smørgrav #endif /* USE_UTMP */
91783d2307dSDag-Erling Smørgrav 
91883d2307dSDag-Erling Smørgrav 
91983d2307dSDag-Erling Smørgrav /**
92083d2307dSDag-Erling Smørgrav  ** Low-level utmpx functions
92183d2307dSDag-Erling Smørgrav  **/
92283d2307dSDag-Erling Smørgrav 
92383d2307dSDag-Erling Smørgrav /* not much point if we don't want utmpx entries */
92483d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX
92583d2307dSDag-Erling Smørgrav 
92683d2307dSDag-Erling Smørgrav /* if we have the wherewithall, use pututxline etc. */
92783d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
92883d2307dSDag-Erling Smørgrav 	defined(HAVE_PUTUTXLINE)
92983d2307dSDag-Erling Smørgrav #  define UTMPX_USE_LIBRARY
93083d2307dSDag-Erling Smørgrav # endif
93183d2307dSDag-Erling Smørgrav 
93283d2307dSDag-Erling Smørgrav 
93383d2307dSDag-Erling Smørgrav /* write a utmpx entry with the system's help (pututxline() and pals) */
93483d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
93583d2307dSDag-Erling Smørgrav static int
93683d2307dSDag-Erling Smørgrav utmpx_write_library(struct logininfo *li, struct utmpx *utx)
93783d2307dSDag-Erling Smørgrav {
93883d2307dSDag-Erling Smørgrav 	setutxent();
93983d2307dSDag-Erling Smørgrav 	pututxline(utx);
94083d2307dSDag-Erling Smørgrav 
94183d2307dSDag-Erling Smørgrav #  ifdef HAVE_ENDUTXENT
94283d2307dSDag-Erling Smørgrav 	endutxent();
94383d2307dSDag-Erling Smørgrav #  endif
94483d2307dSDag-Erling Smørgrav 	return 1;
94583d2307dSDag-Erling Smørgrav }
94683d2307dSDag-Erling Smørgrav 
94783d2307dSDag-Erling Smørgrav # else /* UTMPX_USE_LIBRARY */
94883d2307dSDag-Erling Smørgrav 
94983d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */
95083d2307dSDag-Erling Smørgrav static int
95183d2307dSDag-Erling Smørgrav utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
95283d2307dSDag-Erling Smørgrav {
95383d2307dSDag-Erling Smørgrav 	log("utmpx_write_direct: not implemented!");
95483d2307dSDag-Erling Smørgrav 	return 0;
95583d2307dSDag-Erling Smørgrav }
95683d2307dSDag-Erling Smørgrav # endif /* UTMPX_USE_LIBRARY */
95783d2307dSDag-Erling Smørgrav 
95883d2307dSDag-Erling Smørgrav static int
95983d2307dSDag-Erling Smørgrav utmpx_perform_login(struct logininfo *li)
96083d2307dSDag-Erling Smørgrav {
96183d2307dSDag-Erling Smørgrav 	struct utmpx utx;
96283d2307dSDag-Erling Smørgrav 
96383d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
96483d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
96583d2307dSDag-Erling Smørgrav 	if (!utmpx_write_library(li, &utx)) {
96683d2307dSDag-Erling Smørgrav 		log("utmpx_perform_login: utmp_write_library() failed");
96783d2307dSDag-Erling Smørgrav 		return 0;
96883d2307dSDag-Erling Smørgrav 	}
96983d2307dSDag-Erling Smørgrav # else
97083d2307dSDag-Erling Smørgrav 	if (!utmpx_write_direct(li, &ut)) {
97183d2307dSDag-Erling Smørgrav 		log("utmpx_perform_login: utmp_write_direct() failed");
97283d2307dSDag-Erling Smørgrav 		return 0;
97383d2307dSDag-Erling Smørgrav 	}
97483d2307dSDag-Erling Smørgrav # endif
97583d2307dSDag-Erling Smørgrav 	return 1;
97683d2307dSDag-Erling Smørgrav }
97783d2307dSDag-Erling Smørgrav 
97883d2307dSDag-Erling Smørgrav 
97983d2307dSDag-Erling Smørgrav static int
98083d2307dSDag-Erling Smørgrav utmpx_perform_logout(struct logininfo *li)
98183d2307dSDag-Erling Smørgrav {
98283d2307dSDag-Erling Smørgrav 	struct utmpx utx;
98383d2307dSDag-Erling Smørgrav 
98483d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
98583d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX
98683d2307dSDag-Erling Smørgrav 	line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
98783d2307dSDag-Erling Smørgrav # endif
98883d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX
98983d2307dSDag-Erling Smørgrav 	utx.ut_type = DEAD_PROCESS;
99083d2307dSDag-Erling Smørgrav # endif
99183d2307dSDag-Erling Smørgrav 
99283d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
99383d2307dSDag-Erling Smørgrav 	utmpx_write_library(li, &utx);
99483d2307dSDag-Erling Smørgrav # else
99583d2307dSDag-Erling Smørgrav 	utmpx_write_direct(li, &utx);
99683d2307dSDag-Erling Smørgrav # endif
99783d2307dSDag-Erling Smørgrav 	return 1;
99883d2307dSDag-Erling Smørgrav }
99983d2307dSDag-Erling Smørgrav 
100083d2307dSDag-Erling Smørgrav int
100183d2307dSDag-Erling Smørgrav utmpx_write_entry(struct logininfo *li)
100283d2307dSDag-Erling Smørgrav {
100383d2307dSDag-Erling Smørgrav 	switch(li->type) {
100483d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
100583d2307dSDag-Erling Smørgrav 		return utmpx_perform_login(li);
100683d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
100783d2307dSDag-Erling Smørgrav 		return utmpx_perform_logout(li);
100883d2307dSDag-Erling Smørgrav 	default:
100983d2307dSDag-Erling Smørgrav 		log("utmpx_write_entry: invalid type field");
101083d2307dSDag-Erling Smørgrav 		return 0;
101183d2307dSDag-Erling Smørgrav 	}
101283d2307dSDag-Erling Smørgrav }
101383d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX */
101483d2307dSDag-Erling Smørgrav 
101583d2307dSDag-Erling Smørgrav 
101683d2307dSDag-Erling Smørgrav /**
101783d2307dSDag-Erling Smørgrav  ** Low-level wtmp functions
101883d2307dSDag-Erling Smørgrav  **/
101983d2307dSDag-Erling Smørgrav 
102083d2307dSDag-Erling Smørgrav #ifdef USE_WTMP
102183d2307dSDag-Erling Smørgrav 
102283d2307dSDag-Erling Smørgrav /* write a wtmp entry direct to the end of the file */
102383d2307dSDag-Erling Smørgrav /* This is a slight modification of code in OpenBSD's logwtmp.c */
102483d2307dSDag-Erling Smørgrav static int
102583d2307dSDag-Erling Smørgrav wtmp_write(struct logininfo *li, struct utmp *ut)
102683d2307dSDag-Erling Smørgrav {
102783d2307dSDag-Erling Smørgrav 	struct stat buf;
102883d2307dSDag-Erling Smørgrav 	int fd, ret = 1;
102983d2307dSDag-Erling Smørgrav 
103083d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
103183d2307dSDag-Erling Smørgrav 		log("wtmp_write: problem writing %s: %s",
103283d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
103383d2307dSDag-Erling Smørgrav 		return 0;
103483d2307dSDag-Erling Smørgrav 	}
103583d2307dSDag-Erling Smørgrav 	if (fstat(fd, &buf) == 0)
103683d2307dSDag-Erling Smørgrav 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
103783d2307dSDag-Erling Smørgrav 			ftruncate(fd, buf.st_size);
103883d2307dSDag-Erling Smørgrav 			log("wtmp_write: problem writing %s: %s",
103983d2307dSDag-Erling Smørgrav 			    WTMP_FILE, strerror(errno));
104083d2307dSDag-Erling Smørgrav 			ret = 0;
104183d2307dSDag-Erling Smørgrav 		}
104283d2307dSDag-Erling Smørgrav 	(void)close(fd);
104383d2307dSDag-Erling Smørgrav 	return ret;
104483d2307dSDag-Erling Smørgrav }
104583d2307dSDag-Erling Smørgrav 
104683d2307dSDag-Erling Smørgrav static int
104783d2307dSDag-Erling Smørgrav wtmp_perform_login(struct logininfo *li)
104883d2307dSDag-Erling Smørgrav {
104983d2307dSDag-Erling Smørgrav 	struct utmp ut;
105083d2307dSDag-Erling Smørgrav 
105183d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
105283d2307dSDag-Erling Smørgrav 	return wtmp_write(li, &ut);
105383d2307dSDag-Erling Smørgrav }
105483d2307dSDag-Erling Smørgrav 
105583d2307dSDag-Erling Smørgrav 
105683d2307dSDag-Erling Smørgrav static int
105783d2307dSDag-Erling Smørgrav wtmp_perform_logout(struct logininfo *li)
105883d2307dSDag-Erling Smørgrav {
105983d2307dSDag-Erling Smørgrav 	struct utmp ut;
106083d2307dSDag-Erling Smørgrav 
106183d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
106283d2307dSDag-Erling Smørgrav 	return wtmp_write(li, &ut);
106383d2307dSDag-Erling Smørgrav }
106483d2307dSDag-Erling Smørgrav 
106583d2307dSDag-Erling Smørgrav 
106683d2307dSDag-Erling Smørgrav int
106783d2307dSDag-Erling Smørgrav wtmp_write_entry(struct logininfo *li)
106883d2307dSDag-Erling Smørgrav {
106983d2307dSDag-Erling Smørgrav 	switch(li->type) {
107083d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
107183d2307dSDag-Erling Smørgrav 		return wtmp_perform_login(li);
107283d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
107383d2307dSDag-Erling Smørgrav 		return wtmp_perform_logout(li);
107483d2307dSDag-Erling Smørgrav 	default:
107583d2307dSDag-Erling Smørgrav 		log("wtmp_write_entry: invalid type field");
107683d2307dSDag-Erling Smørgrav 		return 0;
107783d2307dSDag-Erling Smørgrav 	}
107883d2307dSDag-Erling Smørgrav }
107983d2307dSDag-Erling Smørgrav 
108083d2307dSDag-Erling Smørgrav 
108183d2307dSDag-Erling Smørgrav /* Notes on fetching login data from wtmp/wtmpx
108283d2307dSDag-Erling Smørgrav  *
108383d2307dSDag-Erling Smørgrav  * Logouts are usually recorded with (amongst other things) a blank
108483d2307dSDag-Erling Smørgrav  * username on a given tty line.  However, some systems (HP-UX is one)
108583d2307dSDag-Erling Smørgrav  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
108683d2307dSDag-Erling Smørgrav  *
108783d2307dSDag-Erling Smørgrav  * Since we're only looking for logins here, we know that the username
108883d2307dSDag-Erling Smørgrav  * must be set correctly. On systems that leave it in, we check for
108983d2307dSDag-Erling Smørgrav  * ut_type==USER_PROCESS (indicating a login.)
109083d2307dSDag-Erling Smørgrav  *
109183d2307dSDag-Erling Smørgrav  * Portability: Some systems may set something other than USER_PROCESS
109283d2307dSDag-Erling Smørgrav  * to indicate a login process. I don't know of any as I write. Also,
109383d2307dSDag-Erling Smørgrav  * it's possible that some systems may both leave the username in
109483d2307dSDag-Erling Smørgrav  * place and not have ut_type.
109583d2307dSDag-Erling Smørgrav  */
109683d2307dSDag-Erling Smørgrav 
109783d2307dSDag-Erling Smørgrav /* return true if this wtmp entry indicates a login */
109883d2307dSDag-Erling Smørgrav static int
109983d2307dSDag-Erling Smørgrav wtmp_islogin(struct logininfo *li, struct utmp *ut)
110083d2307dSDag-Erling Smørgrav {
110183d2307dSDag-Erling Smørgrav 	if (strncmp(li->username, ut->ut_name,
110283d2307dSDag-Erling Smørgrav 		MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
110383d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP
110483d2307dSDag-Erling Smørgrav 		if (ut->ut_type & USER_PROCESS)
110583d2307dSDag-Erling Smørgrav 			return 1;
110683d2307dSDag-Erling Smørgrav # else
110783d2307dSDag-Erling Smørgrav 		return 1;
110883d2307dSDag-Erling Smørgrav # endif
110983d2307dSDag-Erling Smørgrav 	}
111083d2307dSDag-Erling Smørgrav 	return 0;
111183d2307dSDag-Erling Smørgrav }
111283d2307dSDag-Erling Smørgrav 
111383d2307dSDag-Erling Smørgrav int
111483d2307dSDag-Erling Smørgrav wtmp_get_entry(struct logininfo *li)
111583d2307dSDag-Erling Smørgrav {
111683d2307dSDag-Erling Smørgrav 	struct stat st;
111783d2307dSDag-Erling Smørgrav 	struct utmp ut;
111883d2307dSDag-Erling Smørgrav 	int fd, found=0;
111983d2307dSDag-Erling Smørgrav 
112083d2307dSDag-Erling Smørgrav 	/* Clear the time entries in our logininfo */
112183d2307dSDag-Erling Smørgrav 	li->tv_sec = li->tv_usec = 0;
112283d2307dSDag-Erling Smørgrav 
112383d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
112483d2307dSDag-Erling Smørgrav 		log("wtmp_get_entry: problem opening %s: %s",
112583d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
112683d2307dSDag-Erling Smørgrav 		return 0;
112783d2307dSDag-Erling Smørgrav 	}
112883d2307dSDag-Erling Smørgrav 	if (fstat(fd, &st) != 0) {
112983d2307dSDag-Erling Smørgrav 		log("wtmp_get_entry: couldn't stat %s: %s",
113083d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
113183d2307dSDag-Erling Smørgrav 		close(fd);
113283d2307dSDag-Erling Smørgrav 		return 0;
113383d2307dSDag-Erling Smørgrav 	}
113483d2307dSDag-Erling Smørgrav 
113583d2307dSDag-Erling Smørgrav 	/* Seek to the start of the last struct utmp */
113683d2307dSDag-Erling Smørgrav 	if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
113783d2307dSDag-Erling Smørgrav 		/* Looks like we've got a fresh wtmp file */
113883d2307dSDag-Erling Smørgrav 		close(fd);
113983d2307dSDag-Erling Smørgrav 		return 0;
114083d2307dSDag-Erling Smørgrav 	}
114183d2307dSDag-Erling Smørgrav 
114283d2307dSDag-Erling Smørgrav 	while (!found) {
114383d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
114483d2307dSDag-Erling Smørgrav 			log("wtmp_get_entry: read of %s failed: %s",
114583d2307dSDag-Erling Smørgrav 			    WTMP_FILE, strerror(errno));
114683d2307dSDag-Erling Smørgrav 			close (fd);
114783d2307dSDag-Erling Smørgrav 			return 0;
114883d2307dSDag-Erling Smørgrav 		}
114983d2307dSDag-Erling Smørgrav 		if ( wtmp_islogin(li, &ut) ) {
115083d2307dSDag-Erling Smørgrav 			found = 1;
115183d2307dSDag-Erling Smørgrav 			/* We've already checked for a time in struct
115283d2307dSDag-Erling Smørgrav 			 * utmp, in login_getlast(). */
115383d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMP
115483d2307dSDag-Erling Smørgrav 			li->tv_sec = ut.ut_time;
115583d2307dSDag-Erling Smørgrav # else
115683d2307dSDag-Erling Smørgrav #  if HAVE_TV_IN_UTMP
115783d2307dSDag-Erling Smørgrav 			li->tv_sec = ut.ut_tv.tv_sec;
115883d2307dSDag-Erling Smørgrav #  endif
115983d2307dSDag-Erling Smørgrav # endif
116083d2307dSDag-Erling Smørgrav 			line_fullname(li->line, ut.ut_line,
116183d2307dSDag-Erling Smørgrav 				      MIN_SIZEOF(li->line, ut.ut_line));
116283d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP
116383d2307dSDag-Erling Smørgrav 			strlcpy(li->hostname, ut.ut_host,
116483d2307dSDag-Erling Smørgrav 				MIN_SIZEOF(li->hostname, ut.ut_host));
116583d2307dSDag-Erling Smørgrav # endif
116683d2307dSDag-Erling Smørgrav 			continue;
116783d2307dSDag-Erling Smørgrav 		}
116883d2307dSDag-Erling Smørgrav 		/* Seek back 2 x struct utmp */
116983d2307dSDag-Erling Smørgrav 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
117083d2307dSDag-Erling Smørgrav 			/* We've found the start of the file, so quit */
117183d2307dSDag-Erling Smørgrav 			close (fd);
117283d2307dSDag-Erling Smørgrav 			return 0;
117383d2307dSDag-Erling Smørgrav 		}
117483d2307dSDag-Erling Smørgrav 	}
117583d2307dSDag-Erling Smørgrav 
117683d2307dSDag-Erling Smørgrav 	/* We found an entry. Tidy up and return */
117783d2307dSDag-Erling Smørgrav 	close(fd);
117883d2307dSDag-Erling Smørgrav 	return 1;
117983d2307dSDag-Erling Smørgrav }
118083d2307dSDag-Erling Smørgrav # endif /* USE_WTMP */
118183d2307dSDag-Erling Smørgrav 
118283d2307dSDag-Erling Smørgrav 
118383d2307dSDag-Erling Smørgrav /**
118483d2307dSDag-Erling Smørgrav  ** Low-level wtmpx functions
118583d2307dSDag-Erling Smørgrav  **/
118683d2307dSDag-Erling Smørgrav 
118783d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX
118883d2307dSDag-Erling Smørgrav /* write a wtmpx entry direct to the end of the file */
118983d2307dSDag-Erling Smørgrav /* This is a slight modification of code in OpenBSD's logwtmp.c */
119083d2307dSDag-Erling Smørgrav static int
119183d2307dSDag-Erling Smørgrav wtmpx_write(struct logininfo *li, struct utmpx *utx)
119283d2307dSDag-Erling Smørgrav {
119383d2307dSDag-Erling Smørgrav 	struct stat buf;
119483d2307dSDag-Erling Smørgrav 	int fd, ret = 1;
119583d2307dSDag-Erling Smørgrav 
119683d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
119783d2307dSDag-Erling Smørgrav 		log("wtmpx_write: problem opening %s: %s",
119883d2307dSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
119983d2307dSDag-Erling Smørgrav 		return 0;
120083d2307dSDag-Erling Smørgrav 	}
120183d2307dSDag-Erling Smørgrav 
120283d2307dSDag-Erling Smørgrav 	if (fstat(fd, &buf) == 0)
120383d2307dSDag-Erling Smørgrav 		if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
120483d2307dSDag-Erling Smørgrav 			ftruncate(fd, buf.st_size);
120583d2307dSDag-Erling Smørgrav 			log("wtmpx_write: problem writing %s: %s",
120683d2307dSDag-Erling Smørgrav 			    WTMPX_FILE, strerror(errno));
120783d2307dSDag-Erling Smørgrav 			ret = 0;
120883d2307dSDag-Erling Smørgrav 		}
120983d2307dSDag-Erling Smørgrav 	(void)close(fd);
121083d2307dSDag-Erling Smørgrav 
121183d2307dSDag-Erling Smørgrav 	return ret;
121283d2307dSDag-Erling Smørgrav }
121383d2307dSDag-Erling Smørgrav 
121483d2307dSDag-Erling Smørgrav 
121583d2307dSDag-Erling Smørgrav static int
121683d2307dSDag-Erling Smørgrav wtmpx_perform_login(struct logininfo *li)
121783d2307dSDag-Erling Smørgrav {
121883d2307dSDag-Erling Smørgrav 	struct utmpx utx;
121983d2307dSDag-Erling Smørgrav 
122083d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
122183d2307dSDag-Erling Smørgrav 	return wtmpx_write(li, &utx);
122283d2307dSDag-Erling Smørgrav }
122383d2307dSDag-Erling Smørgrav 
122483d2307dSDag-Erling Smørgrav 
122583d2307dSDag-Erling Smørgrav static int
122683d2307dSDag-Erling Smørgrav wtmpx_perform_logout(struct logininfo *li)
122783d2307dSDag-Erling Smørgrav {
122883d2307dSDag-Erling Smørgrav 	struct utmpx utx;
122983d2307dSDag-Erling Smørgrav 
123083d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
123183d2307dSDag-Erling Smørgrav 	return wtmpx_write(li, &utx);
123283d2307dSDag-Erling Smørgrav }
123383d2307dSDag-Erling Smørgrav 
123483d2307dSDag-Erling Smørgrav 
123583d2307dSDag-Erling Smørgrav int
123683d2307dSDag-Erling Smørgrav wtmpx_write_entry(struct logininfo *li)
123783d2307dSDag-Erling Smørgrav {
123883d2307dSDag-Erling Smørgrav 	switch(li->type) {
123983d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
124083d2307dSDag-Erling Smørgrav 		return wtmpx_perform_login(li);
124183d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
124283d2307dSDag-Erling Smørgrav 		return wtmpx_perform_logout(li);
124383d2307dSDag-Erling Smørgrav 	default:
124483d2307dSDag-Erling Smørgrav 		log("wtmpx_write_entry: invalid type field");
124583d2307dSDag-Erling Smørgrav 		return 0;
124683d2307dSDag-Erling Smørgrav 	}
124783d2307dSDag-Erling Smørgrav }
124883d2307dSDag-Erling Smørgrav 
124983d2307dSDag-Erling Smørgrav /* Please see the notes above wtmp_islogin() for information about the
125083d2307dSDag-Erling Smørgrav    next two functions */
125183d2307dSDag-Erling Smørgrav 
125283d2307dSDag-Erling Smørgrav /* Return true if this wtmpx entry indicates a login */
125383d2307dSDag-Erling Smørgrav static int
125483d2307dSDag-Erling Smørgrav wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
125583d2307dSDag-Erling Smørgrav {
125683d2307dSDag-Erling Smørgrav 	if ( strncmp(li->username, utx->ut_name,
125783d2307dSDag-Erling Smørgrav 		MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
125883d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX
125983d2307dSDag-Erling Smørgrav 		if (utx->ut_type == USER_PROCESS)
126083d2307dSDag-Erling Smørgrav 			return 1;
126183d2307dSDag-Erling Smørgrav # else
126283d2307dSDag-Erling Smørgrav 		return 1;
126383d2307dSDag-Erling Smørgrav # endif
126483d2307dSDag-Erling Smørgrav 	}
126583d2307dSDag-Erling Smørgrav 	return 0;
126683d2307dSDag-Erling Smørgrav }
126783d2307dSDag-Erling Smørgrav 
126883d2307dSDag-Erling Smørgrav 
126983d2307dSDag-Erling Smørgrav int
127083d2307dSDag-Erling Smørgrav wtmpx_get_entry(struct logininfo *li)
127183d2307dSDag-Erling Smørgrav {
127283d2307dSDag-Erling Smørgrav 	struct stat st;
127383d2307dSDag-Erling Smørgrav 	struct utmpx utx;
127483d2307dSDag-Erling Smørgrav 	int fd, found=0;
127583d2307dSDag-Erling Smørgrav 
127683d2307dSDag-Erling Smørgrav 	/* Clear the time entries */
127783d2307dSDag-Erling Smørgrav 	li->tv_sec = li->tv_usec = 0;
127883d2307dSDag-Erling Smørgrav 
127983d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
128083d2307dSDag-Erling Smørgrav 		log("wtmpx_get_entry: problem opening %s: %s",
128183d2307dSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
128283d2307dSDag-Erling Smørgrav 		return 0;
128383d2307dSDag-Erling Smørgrav 	}
128483d2307dSDag-Erling Smørgrav 	if (fstat(fd, &st) != 0) {
128583d2307dSDag-Erling Smørgrav 		log("wtmpx_get_entry: couldn't stat %s: %s",
1286f388f5efSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
128783d2307dSDag-Erling Smørgrav 		close(fd);
128883d2307dSDag-Erling Smørgrav 		return 0;
128983d2307dSDag-Erling Smørgrav 	}
129083d2307dSDag-Erling Smørgrav 
129183d2307dSDag-Erling Smørgrav 	/* Seek to the start of the last struct utmpx */
129283d2307dSDag-Erling Smørgrav 	if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
129383d2307dSDag-Erling Smørgrav 		/* probably a newly rotated wtmpx file */
129483d2307dSDag-Erling Smørgrav 		close(fd);
129583d2307dSDag-Erling Smørgrav 		return 0;
129683d2307dSDag-Erling Smørgrav 	}
129783d2307dSDag-Erling Smørgrav 
129883d2307dSDag-Erling Smørgrav 	while (!found) {
129983d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
130083d2307dSDag-Erling Smørgrav 			log("wtmpx_get_entry: read of %s failed: %s",
130183d2307dSDag-Erling Smørgrav 			    WTMPX_FILE, strerror(errno));
130283d2307dSDag-Erling Smørgrav 			close (fd);
130383d2307dSDag-Erling Smørgrav 			return 0;
130483d2307dSDag-Erling Smørgrav 		}
130583d2307dSDag-Erling Smørgrav 		/* Logouts are recorded as a blank username on a particular line.
130683d2307dSDag-Erling Smørgrav 		 * So, we just need to find the username in struct utmpx */
130783d2307dSDag-Erling Smørgrav 		if ( wtmpx_islogin(li, &utx) ) {
1308f388f5efSDag-Erling Smørgrav 			found = 1;
130983d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMPX
131083d2307dSDag-Erling Smørgrav 			li->tv_sec = utx.ut_tv.tv_sec;
131183d2307dSDag-Erling Smørgrav # else
131283d2307dSDag-Erling Smørgrav #  ifdef HAVE_TIME_IN_UTMPX
131383d2307dSDag-Erling Smørgrav 			li->tv_sec = utx.ut_time;
131483d2307dSDag-Erling Smørgrav #  endif
131583d2307dSDag-Erling Smørgrav # endif
131683d2307dSDag-Erling Smørgrav 			line_fullname(li->line, utx.ut_line, sizeof(li->line));
131783d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX
131883d2307dSDag-Erling Smørgrav 			strlcpy(li->hostname, utx.ut_host,
131983d2307dSDag-Erling Smørgrav 				MIN_SIZEOF(li->hostname, utx.ut_host));
132083d2307dSDag-Erling Smørgrav # endif
132183d2307dSDag-Erling Smørgrav 			continue;
132283d2307dSDag-Erling Smørgrav 		}
132383d2307dSDag-Erling Smørgrav 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
132483d2307dSDag-Erling Smørgrav 			close (fd);
132583d2307dSDag-Erling Smørgrav 			return 0;
132683d2307dSDag-Erling Smørgrav 		}
132783d2307dSDag-Erling Smørgrav 	}
132883d2307dSDag-Erling Smørgrav 
132983d2307dSDag-Erling Smørgrav 	close(fd);
133083d2307dSDag-Erling Smørgrav 	return 1;
133183d2307dSDag-Erling Smørgrav }
133283d2307dSDag-Erling Smørgrav #endif /* USE_WTMPX */
133383d2307dSDag-Erling Smørgrav 
133483d2307dSDag-Erling Smørgrav /**
133583d2307dSDag-Erling Smørgrav  ** Low-level libutil login() functions
133683d2307dSDag-Erling Smørgrav  **/
133783d2307dSDag-Erling Smørgrav 
133883d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN
133983d2307dSDag-Erling Smørgrav static int
134083d2307dSDag-Erling Smørgrav syslogin_perform_login(struct logininfo *li)
134183d2307dSDag-Erling Smørgrav {
134283d2307dSDag-Erling Smørgrav 	struct utmp *ut;
134383d2307dSDag-Erling Smørgrav 
134483d2307dSDag-Erling Smørgrav 	if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
134583d2307dSDag-Erling Smørgrav 		log("syslogin_perform_login: couldn't malloc()");
134683d2307dSDag-Erling Smørgrav 		return 0;
134783d2307dSDag-Erling Smørgrav 	}
134883d2307dSDag-Erling Smørgrav 	construct_utmp(li, ut);
134983d2307dSDag-Erling Smørgrav 	login(ut);
1350e73e9afaSDag-Erling Smørgrav 	free(ut);
135183d2307dSDag-Erling Smørgrav 
135283d2307dSDag-Erling Smørgrav 	return 1;
135383d2307dSDag-Erling Smørgrav }
135483d2307dSDag-Erling Smørgrav 
135583d2307dSDag-Erling Smørgrav static int
135683d2307dSDag-Erling Smørgrav syslogin_perform_logout(struct logininfo *li)
135783d2307dSDag-Erling Smørgrav {
135883d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGOUT
135983d2307dSDag-Erling Smørgrav 	char line[8];
136083d2307dSDag-Erling Smørgrav 
136183d2307dSDag-Erling Smørgrav 	(void)line_stripname(line, li->line, sizeof(line));
136283d2307dSDag-Erling Smørgrav 
136383d2307dSDag-Erling Smørgrav 	if (!logout(line)) {
136483d2307dSDag-Erling Smørgrav 		log("syslogin_perform_logout: logout() returned an error");
136583d2307dSDag-Erling Smørgrav #  ifdef HAVE_LOGWTMP
136683d2307dSDag-Erling Smørgrav 	} else {
136783d2307dSDag-Erling Smørgrav 		logwtmp(line, "", "");
136883d2307dSDag-Erling Smørgrav #  endif
136983d2307dSDag-Erling Smørgrav 	}
137083d2307dSDag-Erling Smørgrav 	/* FIXME: (ATL - if the need arises) What to do if we have
137183d2307dSDag-Erling Smørgrav 	 * login, but no logout?  what if logout but no logwtmp? All
137283d2307dSDag-Erling Smørgrav 	 * routines are in libutil so they should all be there,
137383d2307dSDag-Erling Smørgrav 	 * but... */
137483d2307dSDag-Erling Smørgrav # endif
137583d2307dSDag-Erling Smørgrav 	return 1;
137683d2307dSDag-Erling Smørgrav }
137783d2307dSDag-Erling Smørgrav 
137883d2307dSDag-Erling Smørgrav int
137983d2307dSDag-Erling Smørgrav syslogin_write_entry(struct logininfo *li)
138083d2307dSDag-Erling Smørgrav {
138183d2307dSDag-Erling Smørgrav 	switch (li->type) {
138283d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
138383d2307dSDag-Erling Smørgrav 		return syslogin_perform_login(li);
138483d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
138583d2307dSDag-Erling Smørgrav 		return syslogin_perform_logout(li);
138683d2307dSDag-Erling Smørgrav 	default:
138783d2307dSDag-Erling Smørgrav 		log("syslogin_write_entry: Invalid type field");
138883d2307dSDag-Erling Smørgrav 		return 0;
138983d2307dSDag-Erling Smørgrav 	}
139083d2307dSDag-Erling Smørgrav }
139183d2307dSDag-Erling Smørgrav #endif /* USE_LOGIN */
139283d2307dSDag-Erling Smørgrav 
139383d2307dSDag-Erling Smørgrav /* end of file log-syslogin.c */
139483d2307dSDag-Erling Smørgrav 
139583d2307dSDag-Erling Smørgrav /**
139683d2307dSDag-Erling Smørgrav  ** Low-level lastlog functions
139783d2307dSDag-Erling Smørgrav  **/
139883d2307dSDag-Erling Smørgrav 
139983d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
140083d2307dSDag-Erling Smørgrav #define LL_FILE 1
140183d2307dSDag-Erling Smørgrav #define LL_DIR 2
140283d2307dSDag-Erling Smørgrav #define LL_OTHER 3
140383d2307dSDag-Erling Smørgrav 
140483d2307dSDag-Erling Smørgrav static void
140583d2307dSDag-Erling Smørgrav lastlog_construct(struct logininfo *li, struct lastlog *last)
140683d2307dSDag-Erling Smørgrav {
140783d2307dSDag-Erling Smørgrav 	/* clear the structure */
140883d2307dSDag-Erling Smørgrav 	memset(last, '\0', sizeof(*last));
140983d2307dSDag-Erling Smørgrav 
141083d2307dSDag-Erling Smørgrav 	(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
141183d2307dSDag-Erling Smørgrav 	strlcpy(last->ll_host, li->hostname,
141283d2307dSDag-Erling Smørgrav 		MIN_SIZEOF(last->ll_host, li->hostname));
141383d2307dSDag-Erling Smørgrav 	last->ll_time = li->tv_sec;
141483d2307dSDag-Erling Smørgrav }
141583d2307dSDag-Erling Smørgrav 
141683d2307dSDag-Erling Smørgrav static int
141783d2307dSDag-Erling Smørgrav lastlog_filetype(char *filename)
141883d2307dSDag-Erling Smørgrav {
141983d2307dSDag-Erling Smørgrav 	struct stat st;
142083d2307dSDag-Erling Smørgrav 
142183d2307dSDag-Erling Smørgrav 	if (stat(LASTLOG_FILE, &st) != 0) {
142283d2307dSDag-Erling Smørgrav 		log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
142383d2307dSDag-Erling Smørgrav 			strerror(errno));
142483d2307dSDag-Erling Smørgrav 		return 0;
142583d2307dSDag-Erling Smørgrav 	}
142683d2307dSDag-Erling Smørgrav 	if (S_ISDIR(st.st_mode))
142783d2307dSDag-Erling Smørgrav 		return LL_DIR;
142883d2307dSDag-Erling Smørgrav 	else if (S_ISREG(st.st_mode))
142983d2307dSDag-Erling Smørgrav 		return LL_FILE;
143083d2307dSDag-Erling Smørgrav 	else
143183d2307dSDag-Erling Smørgrav 		return LL_OTHER;
143283d2307dSDag-Erling Smørgrav }
143383d2307dSDag-Erling Smørgrav 
143483d2307dSDag-Erling Smørgrav 
143583d2307dSDag-Erling Smørgrav /* open the file (using filemode) and seek to the login entry */
143683d2307dSDag-Erling Smørgrav static int
143783d2307dSDag-Erling Smørgrav lastlog_openseek(struct logininfo *li, int *fd, int filemode)
143883d2307dSDag-Erling Smørgrav {
143983d2307dSDag-Erling Smørgrav 	off_t offset;
144083d2307dSDag-Erling Smørgrav 	int type;
144183d2307dSDag-Erling Smørgrav 	char lastlog_file[1024];
144283d2307dSDag-Erling Smørgrav 
144383d2307dSDag-Erling Smørgrav 	type = lastlog_filetype(LASTLOG_FILE);
144483d2307dSDag-Erling Smørgrav 	switch (type) {
144583d2307dSDag-Erling Smørgrav 		case LL_FILE:
144683d2307dSDag-Erling Smørgrav 			strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
144783d2307dSDag-Erling Smørgrav 			break;
144883d2307dSDag-Erling Smørgrav 		case LL_DIR:
144983d2307dSDag-Erling Smørgrav 			snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
145083d2307dSDag-Erling Smørgrav 				 LASTLOG_FILE, li->username);
145183d2307dSDag-Erling Smørgrav 			break;
145283d2307dSDag-Erling Smørgrav 		default:
145383d2307dSDag-Erling Smørgrav 			log("lastlog_openseek: %.100s is not a file or directory!",
145483d2307dSDag-Erling Smørgrav 			    LASTLOG_FILE);
145583d2307dSDag-Erling Smørgrav 			return 0;
145683d2307dSDag-Erling Smørgrav 	}
145783d2307dSDag-Erling Smørgrav 
145883d2307dSDag-Erling Smørgrav 	*fd = open(lastlog_file, filemode);
145983d2307dSDag-Erling Smørgrav 	if ( *fd < 0) {
146083d2307dSDag-Erling Smørgrav 		debug("lastlog_openseek: Couldn't open %s: %s",
146183d2307dSDag-Erling Smørgrav 		    lastlog_file, strerror(errno));
146283d2307dSDag-Erling Smørgrav 		return 0;
146383d2307dSDag-Erling Smørgrav 	}
146483d2307dSDag-Erling Smørgrav 
146583d2307dSDag-Erling Smørgrav 	if (type == LL_FILE) {
146683d2307dSDag-Erling Smørgrav 		/* find this uid's offset in the lastlog file */
146783d2307dSDag-Erling Smørgrav 		offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
146883d2307dSDag-Erling Smørgrav 
146983d2307dSDag-Erling Smørgrav 		if ( lseek(*fd, offset, SEEK_SET) != offset ) {
147083d2307dSDag-Erling Smørgrav 			log("lastlog_openseek: %s->lseek(): %s",
147183d2307dSDag-Erling Smørgrav 			 lastlog_file, strerror(errno));
147283d2307dSDag-Erling Smørgrav 			return 0;
147383d2307dSDag-Erling Smørgrav 		}
147483d2307dSDag-Erling Smørgrav 	}
147583d2307dSDag-Erling Smørgrav 
147683d2307dSDag-Erling Smørgrav 	return 1;
147783d2307dSDag-Erling Smørgrav }
147883d2307dSDag-Erling Smørgrav 
147983d2307dSDag-Erling Smørgrav static int
148083d2307dSDag-Erling Smørgrav lastlog_perform_login(struct logininfo *li)
148183d2307dSDag-Erling Smørgrav {
148283d2307dSDag-Erling Smørgrav 	struct lastlog last;
148383d2307dSDag-Erling Smørgrav 	int fd;
148483d2307dSDag-Erling Smørgrav 
148583d2307dSDag-Erling Smørgrav 	/* create our struct lastlog */
148683d2307dSDag-Erling Smørgrav 	lastlog_construct(li, &last);
148783d2307dSDag-Erling Smørgrav 
148883d2307dSDag-Erling Smørgrav 	if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
148983d2307dSDag-Erling Smørgrav 		return(0);
149083d2307dSDag-Erling Smørgrav 
149183d2307dSDag-Erling Smørgrav 	/* write the entry */
149283d2307dSDag-Erling Smørgrav 	if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
149383d2307dSDag-Erling Smørgrav 		close(fd);
149483d2307dSDag-Erling Smørgrav 		log("lastlog_write_filemode: Error writing to %s: %s",
149583d2307dSDag-Erling Smørgrav 		    LASTLOG_FILE, strerror(errno));
149683d2307dSDag-Erling Smørgrav 		return 0;
149783d2307dSDag-Erling Smørgrav 	}
149883d2307dSDag-Erling Smørgrav 
149983d2307dSDag-Erling Smørgrav 	close(fd);
150083d2307dSDag-Erling Smørgrav 	return 1;
150183d2307dSDag-Erling Smørgrav }
150283d2307dSDag-Erling Smørgrav 
150383d2307dSDag-Erling Smørgrav int
150483d2307dSDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li)
150583d2307dSDag-Erling Smørgrav {
150683d2307dSDag-Erling Smørgrav 	switch(li->type) {
150783d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
150883d2307dSDag-Erling Smørgrav 		return lastlog_perform_login(li);
150983d2307dSDag-Erling Smørgrav 	default:
151083d2307dSDag-Erling Smørgrav 		log("lastlog_write_entry: Invalid type field");
151183d2307dSDag-Erling Smørgrav 		return 0;
151283d2307dSDag-Erling Smørgrav 	}
151383d2307dSDag-Erling Smørgrav }
151483d2307dSDag-Erling Smørgrav 
151583d2307dSDag-Erling Smørgrav static void
151683d2307dSDag-Erling Smørgrav lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
151783d2307dSDag-Erling Smørgrav {
151883d2307dSDag-Erling Smørgrav 	line_fullname(li->line, last->ll_line, sizeof(li->line));
151983d2307dSDag-Erling Smørgrav 	strlcpy(li->hostname, last->ll_host,
152083d2307dSDag-Erling Smørgrav 		MIN_SIZEOF(li->hostname, last->ll_host));
152183d2307dSDag-Erling Smørgrav 	li->tv_sec = last->ll_time;
152283d2307dSDag-Erling Smørgrav }
152383d2307dSDag-Erling Smørgrav 
152483d2307dSDag-Erling Smørgrav int
152583d2307dSDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li)
152683d2307dSDag-Erling Smørgrav {
152783d2307dSDag-Erling Smørgrav 	struct lastlog last;
1528e73e9afaSDag-Erling Smørgrav 	int fd, ret;
152983d2307dSDag-Erling Smørgrav 
153083d2307dSDag-Erling Smørgrav 	if (!lastlog_openseek(li, &fd, O_RDONLY))
1531e73e9afaSDag-Erling Smørgrav 		return (0);
153283d2307dSDag-Erling Smørgrav 
1533e73e9afaSDag-Erling Smørgrav 	ret = atomicio(read, fd, &last, sizeof(last));
153483d2307dSDag-Erling Smørgrav 	close(fd);
1535e73e9afaSDag-Erling Smørgrav 
1536e73e9afaSDag-Erling Smørgrav 	switch (ret) {
1537e73e9afaSDag-Erling Smørgrav 	case 0:
1538e73e9afaSDag-Erling Smørgrav 		memset(&last, '\0', sizeof(last));
1539e73e9afaSDag-Erling Smørgrav 		/* FALLTHRU */
1540e73e9afaSDag-Erling Smørgrav 	case sizeof(last):
1541e73e9afaSDag-Erling Smørgrav 		lastlog_populate_entry(li, &last);
1542e73e9afaSDag-Erling Smørgrav 		return (1);
1543e73e9afaSDag-Erling Smørgrav 	case -1:
1544e73e9afaSDag-Erling Smørgrav 		error("%s: Error reading from %s: %s", __func__,
154583d2307dSDag-Erling Smørgrav 		    LASTLOG_FILE, strerror(errno));
1546e73e9afaSDag-Erling Smørgrav 		return (0);
1547e73e9afaSDag-Erling Smørgrav 	default:
1548e73e9afaSDag-Erling Smørgrav 		error("%s: Error reading from %s: Expecting %d, got %d",
1549e73e9afaSDag-Erling Smørgrav 		    __func__, LASTLOG_FILE, sizeof(last), ret);
1550e73e9afaSDag-Erling Smørgrav 		return (0);
155183d2307dSDag-Erling Smørgrav 	}
155283d2307dSDag-Erling Smørgrav 
1553e73e9afaSDag-Erling Smørgrav 	/* NOTREACHED */
1554e73e9afaSDag-Erling Smørgrav 	return (0);
155583d2307dSDag-Erling Smørgrav }
155683d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */
1557