xref: /titanic_44/usr/src/cmd/ssh/sshd/loginrec.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate /*
6*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Andre Lucas.  All rights reserved.
7*7c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1998 Todd C. Miller
8*7c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1996 Jason Downs
9*7c478bd9Sstevel@tonic-gate  * Portions copyright (c) 1996 Theo de Raadt
10*7c478bd9Sstevel@tonic-gate  *
11*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
12*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
13*7c478bd9Sstevel@tonic-gate  * are met:
14*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
15*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
16*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
17*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
18*7c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
19*7c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
20*7c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
21*7c478bd9Sstevel@tonic-gate  *      This product includes software developed by Markus Friedl.
22*7c478bd9Sstevel@tonic-gate  * 4. The name of the author may not be used to endorse or promote products
23*7c478bd9Sstevel@tonic-gate  *    derived from this software without specific prior written permission.
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27*7c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28*7c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29*7c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30*7c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31*7c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32*7c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33*7c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /**
38*7c478bd9Sstevel@tonic-gate  ** loginrec.c:  platform-independent login recording and lastlog retrieval
39*7c478bd9Sstevel@tonic-gate  **/
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate   The new login code explained
43*7c478bd9Sstevel@tonic-gate   ============================
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate   This code attempts to provide a common interface to login recording
46*7c478bd9Sstevel@tonic-gate   (utmp and friends) and last login time retrieval.
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate   Its primary means of achieving this is to use 'struct logininfo', a
49*7c478bd9Sstevel@tonic-gate   union of all the useful fields in the various different types of
50*7c478bd9Sstevel@tonic-gate   system login record structures one finds on UNIX variants.
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate   We depend on autoconf to define which recording methods are to be
53*7c478bd9Sstevel@tonic-gate   used, and which fields are contained in the relevant data structures
54*7c478bd9Sstevel@tonic-gate   on the local system. Many C preprocessor symbols affect which code
55*7c478bd9Sstevel@tonic-gate   gets compiled here.
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate   The code is designed to make it easy to modify a particular
58*7c478bd9Sstevel@tonic-gate   recording method, without affecting other methods nor requiring so
59*7c478bd9Sstevel@tonic-gate   many nested conditional compilation blocks as were commonplace in
60*7c478bd9Sstevel@tonic-gate   the old code.
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate   For login recording, we try to use the local system's libraries as
63*7c478bd9Sstevel@tonic-gate   these are clearly most likely to work correctly. For utmp systems
64*7c478bd9Sstevel@tonic-gate   this usually means login() and logout() or setutent() etc., probably
65*7c478bd9Sstevel@tonic-gate   in libutil, along with logwtmp() etc. On these systems, we fall back
66*7c478bd9Sstevel@tonic-gate   to writing the files directly if we have to, though this method
67*7c478bd9Sstevel@tonic-gate   requires very thorough testing so we do not corrupt local auditing
68*7c478bd9Sstevel@tonic-gate   information. These files and their access methods are very system
69*7c478bd9Sstevel@tonic-gate   specific indeed.
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate   For utmpx systems, the corresponding library functions are
72*7c478bd9Sstevel@tonic-gate   setutxent() etc. To the author's knowledge, all utmpx systems have
73*7c478bd9Sstevel@tonic-gate   these library functions and so no direct write is attempted. If such
74*7c478bd9Sstevel@tonic-gate   a system exists and needs support, direct analogues of the [uw]tmp
75*7c478bd9Sstevel@tonic-gate   code should suffice.
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate   Retrieving the time of last login ('lastlog') is in some ways even
78*7c478bd9Sstevel@tonic-gate   more problemmatic than login recording. Some systems provide a
79*7c478bd9Sstevel@tonic-gate   simple table of all users which we seek based on uid and retrieve a
80*7c478bd9Sstevel@tonic-gate   relatively standard structure. Others record the same information in
81*7c478bd9Sstevel@tonic-gate   a directory with a separate file, and others don't record the
82*7c478bd9Sstevel@tonic-gate   information separately at all. For systems in the latter category,
83*7c478bd9Sstevel@tonic-gate   we look backwards in the wtmp or wtmpx file for the last login entry
84*7c478bd9Sstevel@tonic-gate   for our user. Naturally this is slower and on busy systems could
85*7c478bd9Sstevel@tonic-gate   incur a significant performance penalty.
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate   Calling the new code
88*7c478bd9Sstevel@tonic-gate   --------------------
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate   In OpenSSH all login recording and retrieval is performed in
91*7c478bd9Sstevel@tonic-gate   login.c. Here you'll find working examples. Also, in the logintest.c
92*7c478bd9Sstevel@tonic-gate   program there are more examples.
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate   Internal handler calling method
95*7c478bd9Sstevel@tonic-gate   -------------------------------
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate   When a call is made to login_login() or login_logout(), both
98*7c478bd9Sstevel@tonic-gate   routines set a struct logininfo flag defining which action (log in,
99*7c478bd9Sstevel@tonic-gate   or log out) is to be taken. They both then call login_write(), which
100*7c478bd9Sstevel@tonic-gate   calls whichever of the many structure-specific handlers autoconf
101*7c478bd9Sstevel@tonic-gate   selects for the local system.
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate   The handlers themselves handle system data structure specifics. Both
104*7c478bd9Sstevel@tonic-gate   struct utmp and struct utmpx have utility functions (see
105*7c478bd9Sstevel@tonic-gate   construct_utmp*()) to try to make it simpler to add extra systems
106*7c478bd9Sstevel@tonic-gate   that introduce new features to either structure.
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate   While it may seem terribly wasteful to replicate so much similar
109*7c478bd9Sstevel@tonic-gate   code for each method, experience has shown that maintaining code to
110*7c478bd9Sstevel@tonic-gate   write both struct utmp and utmpx in one function, whilst maintaining
111*7c478bd9Sstevel@tonic-gate   support for all systems whether they have library support or not, is
112*7c478bd9Sstevel@tonic-gate   a difficult and time-consuming task.
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate   Lastlog support proceeds similarly. Functions login_get_lastlog()
115*7c478bd9Sstevel@tonic-gate   (and its OpenSSH-tuned friend login_get_lastlog_time()) call
116*7c478bd9Sstevel@tonic-gate   getlast_entry(), which tries one of three methods to find the last
117*7c478bd9Sstevel@tonic-gate   login time. It uses local system lastlog support if it can,
118*7c478bd9Sstevel@tonic-gate   otherwise it tries wtmp or wtmpx before giving up and returning 0,
119*7c478bd9Sstevel@tonic-gate   meaning "tilt".
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate   Maintenance
122*7c478bd9Sstevel@tonic-gate   -----------
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate   In many cases it's possible to tweak autoconf to select the correct
125*7c478bd9Sstevel@tonic-gate   methods for a particular platform, either by improving the detection
126*7c478bd9Sstevel@tonic-gate   code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
127*7c478bd9Sstevel@tonic-gate   symbols for the platform.
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate   Use logintest to check which symbols are defined before modifying
130*7c478bd9Sstevel@tonic-gate   configure.ac and loginrec.c. (You have to build logintest yourself
131*7c478bd9Sstevel@tonic-gate   with 'make logintest' as it's not built by default.)
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate   Otherwise, patches to the specific method(s) are very helpful!
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate */
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /**
138*7c478bd9Sstevel@tonic-gate  ** TODO:
139*7c478bd9Sstevel@tonic-gate  **   homegrown ttyslot()
140*7c478bd9Sstevel@tonic-gate  **   test, test, test
141*7c478bd9Sstevel@tonic-gate  **
142*7c478bd9Sstevel@tonic-gate  ** Platform status:
143*7c478bd9Sstevel@tonic-gate  ** ----------------
144*7c478bd9Sstevel@tonic-gate  **
145*7c478bd9Sstevel@tonic-gate  ** Known good:
146*7c478bd9Sstevel@tonic-gate  **   Linux (Redhat 6.2, Debian)
147*7c478bd9Sstevel@tonic-gate  **   Solaris
148*7c478bd9Sstevel@tonic-gate  **   HP-UX 10.20 (gcc only)
149*7c478bd9Sstevel@tonic-gate  **   IRIX
150*7c478bd9Sstevel@tonic-gate  **   NeXT - M68k/HPPA/Sparc (4.2/3.3)
151*7c478bd9Sstevel@tonic-gate  **
152*7c478bd9Sstevel@tonic-gate  ** Testing required: Please send reports!
153*7c478bd9Sstevel@tonic-gate  **   NetBSD
154*7c478bd9Sstevel@tonic-gate  **   HP-UX 11
155*7c478bd9Sstevel@tonic-gate  **   AIX
156*7c478bd9Sstevel@tonic-gate  **
157*7c478bd9Sstevel@tonic-gate  ** Platforms with known problems:
158*7c478bd9Sstevel@tonic-gate  **   Some variants of Slackware Linux
159*7c478bd9Sstevel@tonic-gate  **
160*7c478bd9Sstevel@tonic-gate  **/
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate #include "includes.h"
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate #include "ssh.h"
165*7c478bd9Sstevel@tonic-gate #include "xmalloc.h"
166*7c478bd9Sstevel@tonic-gate #include "loginrec.h"
167*7c478bd9Sstevel@tonic-gate #include "log.h"
168*7c478bd9Sstevel@tonic-gate #include "atomicio.h"
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate RCSID("$Id: loginrec.c,v 1.44 2002/09/26 00:38:49 tim Exp $");
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UTIL_H
175*7c478bd9Sstevel@tonic-gate #  include <util.h>
176*7c478bd9Sstevel@tonic-gate #endif
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate #ifdef HAVE_LIBUTIL_H
179*7c478bd9Sstevel@tonic-gate #   include <libutil.h>
180*7c478bd9Sstevel@tonic-gate #endif
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /**
183*7c478bd9Sstevel@tonic-gate  ** prototypes for helper functions in this file
184*7c478bd9Sstevel@tonic-gate  **/
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate #if HAVE_UTMP_H
187*7c478bd9Sstevel@tonic-gate void set_utmp_time(struct logininfo *li, struct utmp *ut);
188*7c478bd9Sstevel@tonic-gate void construct_utmp(struct logininfo *li, struct utmp *ut);
189*7c478bd9Sstevel@tonic-gate #endif
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UTMPX_H
192*7c478bd9Sstevel@tonic-gate void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
193*7c478bd9Sstevel@tonic-gate void construct_utmpx(struct logininfo *li, struct utmpx *ut);
194*7c478bd9Sstevel@tonic-gate #endif
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate int utmp_write_entry(struct logininfo *li);
197*7c478bd9Sstevel@tonic-gate int utmpx_write_entry(struct logininfo *li);
198*7c478bd9Sstevel@tonic-gate int wtmp_write_entry(struct logininfo *li);
199*7c478bd9Sstevel@tonic-gate int wtmpx_write_entry(struct logininfo *li);
200*7c478bd9Sstevel@tonic-gate int lastlog_write_entry(struct logininfo *li);
201*7c478bd9Sstevel@tonic-gate int syslogin_write_entry(struct logininfo *li);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate int getlast_entry(struct logininfo *li);
204*7c478bd9Sstevel@tonic-gate int lastlog_get_entry(struct logininfo *li);
205*7c478bd9Sstevel@tonic-gate int wtmp_get_entry(struct logininfo *li);
206*7c478bd9Sstevel@tonic-gate int wtmpx_get_entry(struct logininfo *li);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /* pick the shortest string */
209*7c478bd9Sstevel@tonic-gate #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate /**
212*7c478bd9Sstevel@tonic-gate  ** platform-independent login functions
213*7c478bd9Sstevel@tonic-gate  **/
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate /* login_login(struct logininfo *)     -Record a login
216*7c478bd9Sstevel@tonic-gate  *
217*7c478bd9Sstevel@tonic-gate  * Call with a pointer to a struct logininfo initialised with
218*7c478bd9Sstevel@tonic-gate  * login_init_entry() or login_alloc_entry()
219*7c478bd9Sstevel@tonic-gate  *
220*7c478bd9Sstevel@tonic-gate  * Returns:
221*7c478bd9Sstevel@tonic-gate  *  >0 if successful
222*7c478bd9Sstevel@tonic-gate  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
223*7c478bd9Sstevel@tonic-gate  */
224*7c478bd9Sstevel@tonic-gate int
225*7c478bd9Sstevel@tonic-gate login_login (struct logininfo *li)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	li->type = LTYPE_LOGIN;
228*7c478bd9Sstevel@tonic-gate 	return login_write(li);
229*7c478bd9Sstevel@tonic-gate }
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate /* login_logout(struct logininfo *)     - Record a logout
233*7c478bd9Sstevel@tonic-gate  *
234*7c478bd9Sstevel@tonic-gate  * Call as with login_login()
235*7c478bd9Sstevel@tonic-gate  *
236*7c478bd9Sstevel@tonic-gate  * Returns:
237*7c478bd9Sstevel@tonic-gate  *  >0 if successful
238*7c478bd9Sstevel@tonic-gate  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
239*7c478bd9Sstevel@tonic-gate  */
240*7c478bd9Sstevel@tonic-gate int
241*7c478bd9Sstevel@tonic-gate login_logout(struct logininfo *li)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	li->type = LTYPE_LOGOUT;
244*7c478bd9Sstevel@tonic-gate 	return login_write(li);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate /* login_get_lastlog_time(int)           - Retrieve the last login time
248*7c478bd9Sstevel@tonic-gate  *
249*7c478bd9Sstevel@tonic-gate  * Retrieve the last login time for the given uid. Will try to use the
250*7c478bd9Sstevel@tonic-gate  * system lastlog facilities if they are available, but will fall back
251*7c478bd9Sstevel@tonic-gate  * to looking in wtmp/wtmpx if necessary
252*7c478bd9Sstevel@tonic-gate  *
253*7c478bd9Sstevel@tonic-gate  * Returns:
254*7c478bd9Sstevel@tonic-gate  *   0 on failure, or if user has never logged in
255*7c478bd9Sstevel@tonic-gate  *   Time in seconds from the epoch if successful
256*7c478bd9Sstevel@tonic-gate  *
257*7c478bd9Sstevel@tonic-gate  * Useful preprocessor symbols:
258*7c478bd9Sstevel@tonic-gate  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
259*7c478bd9Sstevel@tonic-gate  *                    info
260*7c478bd9Sstevel@tonic-gate  *   USE_LASTLOG: If set, indicates the presence of system lastlog
261*7c478bd9Sstevel@tonic-gate  *                facilities. If this and DISABLE_LASTLOG are not set,
262*7c478bd9Sstevel@tonic-gate  *                try to retrieve lastlog information from wtmp/wtmpx.
263*7c478bd9Sstevel@tonic-gate  */
264*7c478bd9Sstevel@tonic-gate #if 0
265*7c478bd9Sstevel@tonic-gate unsigned int
266*7c478bd9Sstevel@tonic-gate login_get_lastlog_time(const int uid)
267*7c478bd9Sstevel@tonic-gate {
268*7c478bd9Sstevel@tonic-gate 	struct logininfo li;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	if (login_get_lastlog(&li, uid))
271*7c478bd9Sstevel@tonic-gate 		return li.tv_sec;
272*7c478bd9Sstevel@tonic-gate 	else
273*7c478bd9Sstevel@tonic-gate 		return 0;
274*7c478bd9Sstevel@tonic-gate }
275*7c478bd9Sstevel@tonic-gate #endif
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate /* login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
278*7c478bd9Sstevel@tonic-gate  *
279*7c478bd9Sstevel@tonic-gate  * Retrieve a logininfo structure populated (only partially) with
280*7c478bd9Sstevel@tonic-gate  * information from the system lastlog data, or from wtmp/wtmpx if no
281*7c478bd9Sstevel@tonic-gate  * system lastlog information exists.
282*7c478bd9Sstevel@tonic-gate  *
283*7c478bd9Sstevel@tonic-gate  * Note this routine must be given a pre-allocated logininfo.
284*7c478bd9Sstevel@tonic-gate  *
285*7c478bd9Sstevel@tonic-gate  * Returns:
286*7c478bd9Sstevel@tonic-gate  *  >0: A pointer to your struct logininfo if successful
287*7c478bd9Sstevel@tonic-gate  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
288*7c478bd9Sstevel@tonic-gate  *
289*7c478bd9Sstevel@tonic-gate  */
290*7c478bd9Sstevel@tonic-gate struct logininfo *
291*7c478bd9Sstevel@tonic-gate login_get_lastlog(struct logininfo *li, const int uid)
292*7c478bd9Sstevel@tonic-gate {
293*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	(void) memset(li, '\0', sizeof(*li));
296*7c478bd9Sstevel@tonic-gate 	li->uid = uid;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	/*
299*7c478bd9Sstevel@tonic-gate 	 * If we don't have a 'real' lastlog, we need the username to
300*7c478bd9Sstevel@tonic-gate 	 * reliably search wtmp(x) for the last login (see
301*7c478bd9Sstevel@tonic-gate 	 * wtmp_get_entry().)
302*7c478bd9Sstevel@tonic-gate 	 */
303*7c478bd9Sstevel@tonic-gate 	pw = getpwuid(uid);
304*7c478bd9Sstevel@tonic-gate 	if (pw == NULL)
305*7c478bd9Sstevel@tonic-gate 		fatal("login_get_lastlog: Cannot find account for uid %i", uid);
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	/* No MIN_SIZEOF here - we absolutely *must not* truncate the
308*7c478bd9Sstevel@tonic-gate 	 * username */
309*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(li->username, pw->pw_name, sizeof(li->username));
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if (getlast_entry(li))
312*7c478bd9Sstevel@tonic-gate 		return li;
313*7c478bd9Sstevel@tonic-gate 	else
314*7c478bd9Sstevel@tonic-gate 		return NULL;
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate /* login_alloc_entry()    - Allocate and initialise a logininfo
319*7c478bd9Sstevel@tonic-gate  *                           structure
320*7c478bd9Sstevel@tonic-gate  *
321*7c478bd9Sstevel@tonic-gate  * This function creates a new struct logininfo, a data structure
322*7c478bd9Sstevel@tonic-gate  * meant to carry the information required to portably record login info.
323*7c478bd9Sstevel@tonic-gate  *
324*7c478bd9Sstevel@tonic-gate  * Returns a pointer to a newly created struct logininfo. If memory
325*7c478bd9Sstevel@tonic-gate  * allocation fails, the program halts.
326*7c478bd9Sstevel@tonic-gate  */
327*7c478bd9Sstevel@tonic-gate struct
328*7c478bd9Sstevel@tonic-gate logininfo *login_alloc_entry(int pid, const char *username,
329*7c478bd9Sstevel@tonic-gate 			     const char *hostname, const char *line,
330*7c478bd9Sstevel@tonic-gate 			     const char *progname)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	struct logininfo *newli;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	newli = (struct logininfo *) xmalloc (sizeof(*newli));
335*7c478bd9Sstevel@tonic-gate 	(void)login_init_entry(newli, pid, username, hostname, line, progname);
336*7c478bd9Sstevel@tonic-gate 	return newli;
337*7c478bd9Sstevel@tonic-gate }
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate /* login_free_entry(struct logininfo *)    - free struct memory */
341*7c478bd9Sstevel@tonic-gate void
342*7c478bd9Sstevel@tonic-gate login_free_entry(struct logininfo *li)
343*7c478bd9Sstevel@tonic-gate {
344*7c478bd9Sstevel@tonic-gate 	xfree(li);
345*7c478bd9Sstevel@tonic-gate }
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate /* login_init_entry()
349*7c478bd9Sstevel@tonic-gate  *                                        - initialise a struct logininfo
350*7c478bd9Sstevel@tonic-gate  *
351*7c478bd9Sstevel@tonic-gate  * Populates a new struct logininfo, a data structure meant to carry
352*7c478bd9Sstevel@tonic-gate  * the information required to portably record login info.
353*7c478bd9Sstevel@tonic-gate  *
354*7c478bd9Sstevel@tonic-gate  * Returns: 1
355*7c478bd9Sstevel@tonic-gate  */
356*7c478bd9Sstevel@tonic-gate int
357*7c478bd9Sstevel@tonic-gate login_init_entry(struct logininfo *li, int pid, const char *username,
358*7c478bd9Sstevel@tonic-gate 		 const char *hostname, const char *line, const char *progname)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	(void) memset(li, 0, sizeof(*li));
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	li->pid = pid;
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/* set the line information */
367*7c478bd9Sstevel@tonic-gate 	if (line)
368*7c478bd9Sstevel@tonic-gate 		(void) line_fullname(li->line, line, sizeof(li->line));
369*7c478bd9Sstevel@tonic-gate 	else
370*7c478bd9Sstevel@tonic-gate 		li->line_null = 1;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	if (progname)
373*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->progname, progname, sizeof(li->progname));
374*7c478bd9Sstevel@tonic-gate 	else
375*7c478bd9Sstevel@tonic-gate 		li->progname_null = 1;
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	if (username) {
378*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->username, username, sizeof(li->username));
379*7c478bd9Sstevel@tonic-gate 		pw = getpwnam(li->username);
380*7c478bd9Sstevel@tonic-gate 		if (pw == NULL)
381*7c478bd9Sstevel@tonic-gate 			fatal("login_init_entry: Cannot find user \"%s\"", li->username);
382*7c478bd9Sstevel@tonic-gate 		li->uid = pw->pw_uid;
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	if (hostname)
386*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(li->hostname, hostname, sizeof(li->hostname));
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	return 1;
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate /* login_set_current_time(struct logininfo *)    - set the current time
392*7c478bd9Sstevel@tonic-gate  *
393*7c478bd9Sstevel@tonic-gate  * Set the current time in a logininfo structure. This function is
394*7c478bd9Sstevel@tonic-gate  * meant to eliminate the need to deal with system dependencies for
395*7c478bd9Sstevel@tonic-gate  * time handling.
396*7c478bd9Sstevel@tonic-gate  */
397*7c478bd9Sstevel@tonic-gate void
398*7c478bd9Sstevel@tonic-gate login_set_current_time(struct logininfo *li)
399*7c478bd9Sstevel@tonic-gate {
400*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tv, NULL);
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	li->tv_sec = tv.tv_sec;
405*7c478bd9Sstevel@tonic-gate 	li->tv_usec = tv.tv_usec;
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate /* copy a sockaddr_* into our logininfo */
409*7c478bd9Sstevel@tonic-gate void
410*7c478bd9Sstevel@tonic-gate login_set_addr(struct logininfo *li, const struct sockaddr *sa,
411*7c478bd9Sstevel@tonic-gate 	       const unsigned int sa_size)
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	unsigned int bufsize = sa_size;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/* make sure we don't overrun our union */
416*7c478bd9Sstevel@tonic-gate 	if (sizeof(li->hostaddr) < sa_size)
417*7c478bd9Sstevel@tonic-gate 		bufsize = sizeof(li->hostaddr);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate /**
424*7c478bd9Sstevel@tonic-gate  ** login_write: Call low-level recording functions based on autoconf
425*7c478bd9Sstevel@tonic-gate  ** results
426*7c478bd9Sstevel@tonic-gate  **/
427*7c478bd9Sstevel@tonic-gate int
428*7c478bd9Sstevel@tonic-gate login_write (struct logininfo *li)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate #ifndef HAVE_CYGWIN
431*7c478bd9Sstevel@tonic-gate 	if ((int)geteuid() != 0) {
432*7c478bd9Sstevel@tonic-gate 	  log("Attempt to write login records by non-root user (aborting)");
433*7c478bd9Sstevel@tonic-gate 	  return 1;
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate #endif
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	/* set the timestamp */
438*7c478bd9Sstevel@tonic-gate 	login_set_current_time(li);
439*7c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN
440*7c478bd9Sstevel@tonic-gate 	syslogin_write_entry(li);
441*7c478bd9Sstevel@tonic-gate #endif
442*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG
443*7c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGIN) {
444*7c478bd9Sstevel@tonic-gate 		(void) lastlog_write_entry(li);
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate #endif
447*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMP
448*7c478bd9Sstevel@tonic-gate 	utmp_write_entry(li);
449*7c478bd9Sstevel@tonic-gate #endif
450*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMP
451*7c478bd9Sstevel@tonic-gate 	wtmp_write_entry(li);
452*7c478bd9Sstevel@tonic-gate #endif
453*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX
454*7c478bd9Sstevel@tonic-gate 	(void) utmpx_write_entry(li);
455*7c478bd9Sstevel@tonic-gate #endif
456*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX
457*7c478bd9Sstevel@tonic-gate 	(void) wtmpx_write_entry(li);
458*7c478bd9Sstevel@tonic-gate #endif
459*7c478bd9Sstevel@tonic-gate 	return 0;
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate #ifdef LOGIN_NEEDS_UTMPX
463*7c478bd9Sstevel@tonic-gate int
464*7c478bd9Sstevel@tonic-gate login_utmp_only(struct logininfo *li)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	li->type = LTYPE_LOGIN;
467*7c478bd9Sstevel@tonic-gate 	login_set_current_time(li);
468*7c478bd9Sstevel@tonic-gate # ifdef USE_UTMP
469*7c478bd9Sstevel@tonic-gate 	utmp_write_entry(li);
470*7c478bd9Sstevel@tonic-gate # endif
471*7c478bd9Sstevel@tonic-gate # ifdef USE_WTMP
472*7c478bd9Sstevel@tonic-gate 	wtmp_write_entry(li);
473*7c478bd9Sstevel@tonic-gate # endif
474*7c478bd9Sstevel@tonic-gate # ifdef USE_UTMPX
475*7c478bd9Sstevel@tonic-gate 	(void) utmpx_write_entry(li);
476*7c478bd9Sstevel@tonic-gate # endif
477*7c478bd9Sstevel@tonic-gate # ifdef USE_WTMPX
478*7c478bd9Sstevel@tonic-gate 	(void) wtmpx_write_entry(li);
479*7c478bd9Sstevel@tonic-gate # endif
480*7c478bd9Sstevel@tonic-gate 	return 0;
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate #endif
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate /**
485*7c478bd9Sstevel@tonic-gate  ** getlast_entry: Call low-level functions to retrieve the last login
486*7c478bd9Sstevel@tonic-gate  **                time.
487*7c478bd9Sstevel@tonic-gate  **/
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate /* take the uid in li and return the last login time */
490*7c478bd9Sstevel@tonic-gate int
491*7c478bd9Sstevel@tonic-gate getlast_entry(struct logininfo *li)
492*7c478bd9Sstevel@tonic-gate {
493*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG
494*7c478bd9Sstevel@tonic-gate 	return(lastlog_get_entry(li));
495*7c478bd9Sstevel@tonic-gate #else /* !USE_LASTLOG */
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate #ifdef DISABLE_LASTLOG
498*7c478bd9Sstevel@tonic-gate 	/* On some systems we shouldn't even try to obtain last login
499*7c478bd9Sstevel@tonic-gate 	 * time, e.g. AIX */
500*7c478bd9Sstevel@tonic-gate 	return 0;
501*7c478bd9Sstevel@tonic-gate # else /* DISABLE_LASTLOG */
502*7c478bd9Sstevel@tonic-gate 	/* Try to retrieve the last login time from wtmp */
503*7c478bd9Sstevel@tonic-gate #  if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
504*7c478bd9Sstevel@tonic-gate 	/* retrieve last login time from utmp */
505*7c478bd9Sstevel@tonic-gate 	return (wtmp_get_entry(li));
506*7c478bd9Sstevel@tonic-gate #  else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
507*7c478bd9Sstevel@tonic-gate 	/* If wtmp isn't available, try wtmpx */
508*7c478bd9Sstevel@tonic-gate #   if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
509*7c478bd9Sstevel@tonic-gate 	/* retrieve last login time from utmpx */
510*7c478bd9Sstevel@tonic-gate 	return (wtmpx_get_entry(li));
511*7c478bd9Sstevel@tonic-gate #   else
512*7c478bd9Sstevel@tonic-gate 	/* Give up: No means of retrieving last login time */
513*7c478bd9Sstevel@tonic-gate 	return 0;
514*7c478bd9Sstevel@tonic-gate #   endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
515*7c478bd9Sstevel@tonic-gate #  endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
516*7c478bd9Sstevel@tonic-gate # endif /* DISABLE_LASTLOG */
517*7c478bd9Sstevel@tonic-gate #endif /* USE_LASTLOG */
518*7c478bd9Sstevel@tonic-gate }
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate /*
523*7c478bd9Sstevel@tonic-gate  * 'line' string utility functions
524*7c478bd9Sstevel@tonic-gate  *
525*7c478bd9Sstevel@tonic-gate  * These functions process the 'line' string into one of three forms:
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * 1. The full filename (including '/dev')
528*7c478bd9Sstevel@tonic-gate  * 2. The stripped name (excluding '/dev')
529*7c478bd9Sstevel@tonic-gate  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
530*7c478bd9Sstevel@tonic-gate  *                               /dev/pts/1  -> ts/1 )
531*7c478bd9Sstevel@tonic-gate  *
532*7c478bd9Sstevel@tonic-gate  * Form 3 is used on some systems to identify a .tmp.? entry when
533*7c478bd9Sstevel@tonic-gate  * attempting to remove it. Typically both addition and removal is
534*7c478bd9Sstevel@tonic-gate  * performed by one application - say, sshd - so as long as the choice
535*7c478bd9Sstevel@tonic-gate  * uniquely identifies a terminal it's ok.
536*7c478bd9Sstevel@tonic-gate  */
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate /* line_fullname(): add the leading '/dev/' if it doesn't exist make
540*7c478bd9Sstevel@tonic-gate  * sure dst has enough space, if not just copy src (ugh) */
541*7c478bd9Sstevel@tonic-gate char *
542*7c478bd9Sstevel@tonic-gate line_fullname(char *dst, const char *src, int dstsize)
543*7c478bd9Sstevel@tonic-gate {
544*7c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
545*7c478bd9Sstevel@tonic-gate 	/* "sshd" is special, like "ftp" */
546*7c478bd9Sstevel@tonic-gate 	if (strcmp(src, "sshd") ||
547*7c478bd9Sstevel@tonic-gate 	    ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))) {
548*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src, dstsize);
549*7c478bd9Sstevel@tonic-gate 	} else {
550*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, "/dev/", dstsize);
551*7c478bd9Sstevel@tonic-gate 		(void) strlcat(dst, src, dstsize);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 	return dst;
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate /* line_stripname(): strip the leading '/dev' if it exists, return dst */
557*7c478bd9Sstevel@tonic-gate char *
558*7c478bd9Sstevel@tonic-gate line_stripname(char *dst, const char *src, int dstsize)
559*7c478bd9Sstevel@tonic-gate {
560*7c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
561*7c478bd9Sstevel@tonic-gate 	if (strncmp(src, "/dev/", 5) == 0)
562*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src + 5, dstsize);
563*7c478bd9Sstevel@tonic-gate 	else
564*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(dst, src, dstsize);
565*7c478bd9Sstevel@tonic-gate 	return dst;
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate /* line_abbrevname(): Return the abbreviated (usually four-character)
569*7c478bd9Sstevel@tonic-gate  * form of the line (Just use the last <dstsize> characters of the
570*7c478bd9Sstevel@tonic-gate  * full name.)
571*7c478bd9Sstevel@tonic-gate  *
572*7c478bd9Sstevel@tonic-gate  * NOTE: use strncpy because we do NOT necessarily want zero
573*7c478bd9Sstevel@tonic-gate  * termination */
574*7c478bd9Sstevel@tonic-gate char *
575*7c478bd9Sstevel@tonic-gate line_abbrevname(char *dst, const char *src, int dstsize)
576*7c478bd9Sstevel@tonic-gate {
577*7c478bd9Sstevel@tonic-gate 	size_t len;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	(void) memset(dst, '\0', dstsize);
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	/* Always skip prefix if present */
582*7c478bd9Sstevel@tonic-gate 	if (strncmp(src, "/dev/", 5) == 0)
583*7c478bd9Sstevel@tonic-gate 		src += 5;
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate #ifdef WITH_ABBREV_NO_TTY
586*7c478bd9Sstevel@tonic-gate 	if (strncmp(src, "tty", 3) == 0)
587*7c478bd9Sstevel@tonic-gate 		src += 3;
588*7c478bd9Sstevel@tonic-gate #endif
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	len = strlen(src);
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	if (len > 0) {
593*7c478bd9Sstevel@tonic-gate 		if (((int)len - dstsize) > 0)
594*7c478bd9Sstevel@tonic-gate 			src +=  ((int)len - dstsize);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 		/* note: _don't_ change this to strlcpy */
597*7c478bd9Sstevel@tonic-gate 		(void) strncpy(dst, src, (size_t)dstsize);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	return dst;
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate /**
604*7c478bd9Sstevel@tonic-gate  ** utmp utility functions
605*7c478bd9Sstevel@tonic-gate  **
606*7c478bd9Sstevel@tonic-gate  ** These functions manipulate struct utmp, taking system differences
607*7c478bd9Sstevel@tonic-gate  ** into account.
608*7c478bd9Sstevel@tonic-gate  **/
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate /* build the utmp structure */
613*7c478bd9Sstevel@tonic-gate void
614*7c478bd9Sstevel@tonic-gate set_utmp_time(struct logininfo *li, struct utmp *ut)
615*7c478bd9Sstevel@tonic-gate {
616*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMP
617*7c478bd9Sstevel@tonic-gate 	ut->ut_tv.tv_sec = li->tv_sec;
618*7c478bd9Sstevel@tonic-gate 	ut->ut_tv.tv_usec = li->tv_usec;
619*7c478bd9Sstevel@tonic-gate # else
620*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMP
621*7c478bd9Sstevel@tonic-gate 	ut->ut_time = li->tv_sec;
622*7c478bd9Sstevel@tonic-gate #  endif
623*7c478bd9Sstevel@tonic-gate # endif
624*7c478bd9Sstevel@tonic-gate }
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate void
627*7c478bd9Sstevel@tonic-gate construct_utmp(struct logininfo *li,
628*7c478bd9Sstevel@tonic-gate 		    struct utmp *ut)
629*7c478bd9Sstevel@tonic-gate {
630*7c478bd9Sstevel@tonic-gate 	(void) memset(ut, '\0', sizeof(*ut));
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	/* First fill out fields used for both logins and logouts */
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMP
635*7c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
636*7c478bd9Sstevel@tonic-gate # endif
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP
639*7c478bd9Sstevel@tonic-gate 	/* This is done here to keep utmp constants out of struct logininfo */
640*7c478bd9Sstevel@tonic-gate 	switch (li->type) {
641*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
642*7c478bd9Sstevel@tonic-gate 		ut->ut_type = USER_PROCESS;
643*7c478bd9Sstevel@tonic-gate #ifdef _UNICOS
644*7c478bd9Sstevel@tonic-gate 		cray_set_tmpdir(ut);
645*7c478bd9Sstevel@tonic-gate #endif
646*7c478bd9Sstevel@tonic-gate 		break;
647*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
648*7c478bd9Sstevel@tonic-gate 		ut->ut_type = DEAD_PROCESS;
649*7c478bd9Sstevel@tonic-gate #ifdef _UNICOS
650*7c478bd9Sstevel@tonic-gate 		cray_retain_utmp(ut, li->pid);
651*7c478bd9Sstevel@tonic-gate #endif
652*7c478bd9Sstevel@tonic-gate 		break;
653*7c478bd9Sstevel@tonic-gate 	}
654*7c478bd9Sstevel@tonic-gate # endif
655*7c478bd9Sstevel@tonic-gate 	set_utmp_time(li, ut);
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	(void) line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate # ifdef HAVE_PID_IN_UTMP
660*7c478bd9Sstevel@tonic-gate 	ut->ut_pid = li->pid;
661*7c478bd9Sstevel@tonic-gate # endif
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	/* If we're logging out, leave all other fields blank */
664*7c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGOUT)
665*7c478bd9Sstevel@tonic-gate 	  return;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	/*
668*7c478bd9Sstevel@tonic-gate 	 * These fields are only used when logging in, and are blank
669*7c478bd9Sstevel@tonic-gate 	 * for logouts.
670*7c478bd9Sstevel@tonic-gate 	 */
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	/* Use strncpy because we don't necessarily want null termination */
673*7c478bd9Sstevel@tonic-gate 	(void) strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
674*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP
675*7c478bd9Sstevel@tonic-gate 	(void) strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
676*7c478bd9Sstevel@tonic-gate # endif
677*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMP
678*7c478bd9Sstevel@tonic-gate 	/* this is just a 32-bit IP address */
679*7c478bd9Sstevel@tonic-gate 	if (li->hostaddr.sa.sa_family == AF_INET)
680*7c478bd9Sstevel@tonic-gate 		ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
681*7c478bd9Sstevel@tonic-gate # endif
682*7c478bd9Sstevel@tonic-gate }
683*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate /**
686*7c478bd9Sstevel@tonic-gate  ** utmpx utility functions
687*7c478bd9Sstevel@tonic-gate  **
688*7c478bd9Sstevel@tonic-gate  ** These functions manipulate struct utmpx, accounting for system
689*7c478bd9Sstevel@tonic-gate  ** variations.
690*7c478bd9Sstevel@tonic-gate  **/
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate #if defined(USE_UTMPX) || defined (USE_WTMPX)
693*7c478bd9Sstevel@tonic-gate /* build the utmpx structure */
694*7c478bd9Sstevel@tonic-gate void
695*7c478bd9Sstevel@tonic-gate set_utmpx_time(struct logininfo *li, struct utmpx *utx)
696*7c478bd9Sstevel@tonic-gate {
697*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX
698*7c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_sec = li->tv_sec;
699*7c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_usec = li->tv_usec;
700*7c478bd9Sstevel@tonic-gate # else /* HAVE_TV_IN_UTMPX */
701*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMPX
702*7c478bd9Sstevel@tonic-gate 	utx->ut_time = li->tv_sec;
703*7c478bd9Sstevel@tonic-gate #  endif /* HAVE_TIME_IN_UTMPX */
704*7c478bd9Sstevel@tonic-gate # endif /* HAVE_TV_IN_UTMPX */
705*7c478bd9Sstevel@tonic-gate }
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate void
708*7c478bd9Sstevel@tonic-gate construct_utmpx(struct logininfo *li, struct utmpx *utx)
709*7c478bd9Sstevel@tonic-gate {
710*7c478bd9Sstevel@tonic-gate 	(void) memset(utx, '\0', sizeof(*utx));
711*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX
712*7c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
713*7c478bd9Sstevel@tonic-gate # endif
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	/* this is done here to keep utmp constants out of loginrec.h */
716*7c478bd9Sstevel@tonic-gate 	switch (li->type) {
717*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
718*7c478bd9Sstevel@tonic-gate 		utx->ut_type = USER_PROCESS;
719*7c478bd9Sstevel@tonic-gate 		break;
720*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
721*7c478bd9Sstevel@tonic-gate 		utx->ut_type = DEAD_PROCESS;
722*7c478bd9Sstevel@tonic-gate 		break;
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 	if (!li->line_null)
725*7c478bd9Sstevel@tonic-gate 		(void) line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
726*7c478bd9Sstevel@tonic-gate 	else if (!li->progname_null)
727*7c478bd9Sstevel@tonic-gate 		(void) line_stripname(utx->ut_line, li->progname, sizeof(utx->ut_line));
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	set_utmpx_time(li, utx);
730*7c478bd9Sstevel@tonic-gate 	utx->ut_pid = li->pid;
731*7c478bd9Sstevel@tonic-gate 	/* strncpy(): Don't necessarily want null termination */
732*7c478bd9Sstevel@tonic-gate 	(void) strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	if (li->type == LTYPE_LOGOUT)
735*7c478bd9Sstevel@tonic-gate 		return;
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	/*
738*7c478bd9Sstevel@tonic-gate 	 * These fields are only used when logging in, and are blank
739*7c478bd9Sstevel@tonic-gate 	 * for logouts.
740*7c478bd9Sstevel@tonic-gate 	 */
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX
743*7c478bd9Sstevel@tonic-gate 	(void) strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
744*7c478bd9Sstevel@tonic-gate # endif
745*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMPX
746*7c478bd9Sstevel@tonic-gate 	/* this is just a 32-bit IP address */
747*7c478bd9Sstevel@tonic-gate 	if (li->hostaddr.sa.sa_family == AF_INET)
748*7c478bd9Sstevel@tonic-gate 		utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
749*7c478bd9Sstevel@tonic-gate # endif
750*7c478bd9Sstevel@tonic-gate # ifdef HAVE_SYSLEN_IN_UTMPX
751*7c478bd9Sstevel@tonic-gate 	/* ut_syslen is the length of the utx_host string */
752*7c478bd9Sstevel@tonic-gate 	utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
753*7c478bd9Sstevel@tonic-gate # endif
754*7c478bd9Sstevel@tonic-gate }
755*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX || USE_WTMPX */
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate /**
758*7c478bd9Sstevel@tonic-gate  ** Low-level utmp functions
759*7c478bd9Sstevel@tonic-gate  **/
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate /* FIXME: (ATL) utmp_write_direct needs testing */
762*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMP
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate /* if we can, use pututline() etc. */
765*7c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
766*7c478bd9Sstevel@tonic-gate 	defined(HAVE_PUTUTLINE)
767*7c478bd9Sstevel@tonic-gate #  define UTMP_USE_LIBRARY
768*7c478bd9Sstevel@tonic-gate # endif
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate /* write a utmp entry with the system's help (pututline() and pals) */
772*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
773*7c478bd9Sstevel@tonic-gate static int
774*7c478bd9Sstevel@tonic-gate utmp_write_library(struct logininfo *li, struct utmp *ut)
775*7c478bd9Sstevel@tonic-gate {
776*7c478bd9Sstevel@tonic-gate 	setutent();
777*7c478bd9Sstevel@tonic-gate 	pututline(ut);
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_ENDUTENT
780*7c478bd9Sstevel@tonic-gate 	endutent();
781*7c478bd9Sstevel@tonic-gate #  endif
782*7c478bd9Sstevel@tonic-gate 	return 1;
783*7c478bd9Sstevel@tonic-gate }
784*7c478bd9Sstevel@tonic-gate # else /* UTMP_USE_LIBRARY */
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */
787*7c478bd9Sstevel@tonic-gate /* This is a slightly modification of code in OpenBSD's login.c */
788*7c478bd9Sstevel@tonic-gate static int
789*7c478bd9Sstevel@tonic-gate utmp_write_direct(struct logininfo *li, struct utmp *ut)
790*7c478bd9Sstevel@tonic-gate {
791*7c478bd9Sstevel@tonic-gate 	struct utmp old_ut;
792*7c478bd9Sstevel@tonic-gate 	register int fd;
793*7c478bd9Sstevel@tonic-gate 	int tty;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	/* FIXME: (ATL) ttyslot() needs local implementation */
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate #if defined(HAVE_GETTTYENT)
798*7c478bd9Sstevel@tonic-gate 	register struct ttyent *ty;
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	tty=0;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	setttyent();
803*7c478bd9Sstevel@tonic-gate 	while ((struct ttyent *)0 != (ty = getttyent())) {
804*7c478bd9Sstevel@tonic-gate 		tty++;
805*7c478bd9Sstevel@tonic-gate 		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
806*7c478bd9Sstevel@tonic-gate 			break;
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 	endttyent();
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	if((struct ttyent *)0 == ty) {
811*7c478bd9Sstevel@tonic-gate 		log("utmp_write_entry: tty not found");
812*7c478bd9Sstevel@tonic-gate 		return(1);
813*7c478bd9Sstevel@tonic-gate 	}
814*7c478bd9Sstevel@tonic-gate #else /* FIXME */
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate #endif /* HAVE_GETTTYENT */
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
821*7c478bd9Sstevel@tonic-gate 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
822*7c478bd9Sstevel@tonic-gate 		/*
823*7c478bd9Sstevel@tonic-gate 		 * Prevent luser from zero'ing out ut_host.
824*7c478bd9Sstevel@tonic-gate 		 * If the new ut_line is empty but the old one is not
825*7c478bd9Sstevel@tonic-gate 		 * and ut_line and ut_name match, preserve the old ut_line.
826*7c478bd9Sstevel@tonic-gate 		 */
827*7c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
828*7c478bd9Sstevel@tonic-gate 			(ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
829*7c478bd9Sstevel@tonic-gate 			(strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
830*7c478bd9Sstevel@tonic-gate 			(strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
831*7c478bd9Sstevel@tonic-gate 			(void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
835*7c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
836*7c478bd9Sstevel@tonic-gate 			log("utmp_write_direct: error writing %s: %s",
837*7c478bd9Sstevel@tonic-gate 			    UTMP_FILE, strerror(errno));
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		(void)close(fd);
840*7c478bd9Sstevel@tonic-gate 		return 1;
841*7c478bd9Sstevel@tonic-gate 	} else {
842*7c478bd9Sstevel@tonic-gate 		return 0;
843*7c478bd9Sstevel@tonic-gate 	}
844*7c478bd9Sstevel@tonic-gate }
845*7c478bd9Sstevel@tonic-gate # endif /* UTMP_USE_LIBRARY */
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate static int
848*7c478bd9Sstevel@tonic-gate utmp_perform_login(struct logininfo *li)
849*7c478bd9Sstevel@tonic-gate {
850*7c478bd9Sstevel@tonic-gate 	struct utmp ut;
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
853*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
854*7c478bd9Sstevel@tonic-gate 	if (!utmp_write_library(li, &ut)) {
855*7c478bd9Sstevel@tonic-gate 		log("utmp_perform_login: utmp_write_library() failed");
856*7c478bd9Sstevel@tonic-gate 		return 0;
857*7c478bd9Sstevel@tonic-gate 	}
858*7c478bd9Sstevel@tonic-gate # else
859*7c478bd9Sstevel@tonic-gate 	if (!utmp_write_direct(li, &ut)) {
860*7c478bd9Sstevel@tonic-gate 		log("utmp_perform_login: utmp_write_direct() failed");
861*7c478bd9Sstevel@tonic-gate 		return 0;
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate # endif
864*7c478bd9Sstevel@tonic-gate 	return 1;
865*7c478bd9Sstevel@tonic-gate }
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate static int
869*7c478bd9Sstevel@tonic-gate utmp_perform_logout(struct logininfo *li)
870*7c478bd9Sstevel@tonic-gate {
871*7c478bd9Sstevel@tonic-gate 	struct utmp ut;
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
874*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY
875*7c478bd9Sstevel@tonic-gate 	if (!utmp_write_library(li, &ut)) {
876*7c478bd9Sstevel@tonic-gate 		log("utmp_perform_logout: utmp_write_library() failed");
877*7c478bd9Sstevel@tonic-gate 		return 0;
878*7c478bd9Sstevel@tonic-gate 	}
879*7c478bd9Sstevel@tonic-gate # else
880*7c478bd9Sstevel@tonic-gate 	if (!utmp_write_direct(li, &ut)) {
881*7c478bd9Sstevel@tonic-gate 		log("utmp_perform_logout: utmp_write_direct() failed");
882*7c478bd9Sstevel@tonic-gate 		return 0;
883*7c478bd9Sstevel@tonic-gate 	}
884*7c478bd9Sstevel@tonic-gate # endif
885*7c478bd9Sstevel@tonic-gate 	return 1;
886*7c478bd9Sstevel@tonic-gate }
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate int
890*7c478bd9Sstevel@tonic-gate utmp_write_entry(struct logininfo *li)
891*7c478bd9Sstevel@tonic-gate {
892*7c478bd9Sstevel@tonic-gate 	if (li->line_null) {
893*7c478bd9Sstevel@tonic-gate 		debug3("not writing utmp entry");
894*7c478bd9Sstevel@tonic-gate 		return 1;
895*7c478bd9Sstevel@tonic-gate 	}
896*7c478bd9Sstevel@tonic-gate 	debug3("writing utmp entry");
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	switch(li->type) {
899*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
900*7c478bd9Sstevel@tonic-gate 		return utmp_perform_login(li);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
903*7c478bd9Sstevel@tonic-gate 		return utmp_perform_logout(li);
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	default:
906*7c478bd9Sstevel@tonic-gate 		log("utmp_write_entry: invalid type field");
907*7c478bd9Sstevel@tonic-gate 		return 0;
908*7c478bd9Sstevel@tonic-gate 	}
909*7c478bd9Sstevel@tonic-gate }
910*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMP */
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate /**
914*7c478bd9Sstevel@tonic-gate  ** Low-level utmpx functions
915*7c478bd9Sstevel@tonic-gate  **/
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate /* not much point if we don't want utmpx entries */
918*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate /* if we have the wherewithall, use pututxline etc. */
921*7c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
922*7c478bd9Sstevel@tonic-gate 	defined(HAVE_PUTUTXLINE)
923*7c478bd9Sstevel@tonic-gate #  define UTMPX_USE_LIBRARY
924*7c478bd9Sstevel@tonic-gate # endif
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate /* write a utmpx entry with the system's help (pututxline() and pals) */
928*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
929*7c478bd9Sstevel@tonic-gate static int
930*7c478bd9Sstevel@tonic-gate utmpx_write_library(struct logininfo *li, struct utmpx *utx)
931*7c478bd9Sstevel@tonic-gate {
932*7c478bd9Sstevel@tonic-gate 	setutxent();
933*7c478bd9Sstevel@tonic-gate 	(void) pututxline(utx);
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_ENDUTXENT
936*7c478bd9Sstevel@tonic-gate 	endutxent();
937*7c478bd9Sstevel@tonic-gate #  endif
938*7c478bd9Sstevel@tonic-gate 	return 1;
939*7c478bd9Sstevel@tonic-gate }
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate # else /* UTMPX_USE_LIBRARY */
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */
944*7c478bd9Sstevel@tonic-gate static int
945*7c478bd9Sstevel@tonic-gate utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	log("utmpx_write_direct: not implemented!");
948*7c478bd9Sstevel@tonic-gate 	return 0;
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate # endif /* UTMPX_USE_LIBRARY */
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate static int
953*7c478bd9Sstevel@tonic-gate utmpx_perform_login(struct logininfo *li)
954*7c478bd9Sstevel@tonic-gate {
955*7c478bd9Sstevel@tonic-gate 	struct utmpx utx;
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
958*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
959*7c478bd9Sstevel@tonic-gate 	if (!utmpx_write_library(li, &utx)) {
960*7c478bd9Sstevel@tonic-gate 		log("tmpx_perform_login: utmp_write_library() failed");
961*7c478bd9Sstevel@tonic-gate 		return 0;
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate # else
964*7c478bd9Sstevel@tonic-gate 	if (!utmpx_write_direct(li, &ut)) {
965*7c478bd9Sstevel@tonic-gate 		log("utmpx_perform_login: utmp_write_direct() failed");
966*7c478bd9Sstevel@tonic-gate 		return 0;
967*7c478bd9Sstevel@tonic-gate 	}
968*7c478bd9Sstevel@tonic-gate # endif
969*7c478bd9Sstevel@tonic-gate 	return 1;
970*7c478bd9Sstevel@tonic-gate }
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate static int
974*7c478bd9Sstevel@tonic-gate utmpx_perform_logout(struct logininfo *li)
975*7c478bd9Sstevel@tonic-gate {
976*7c478bd9Sstevel@tonic-gate 	struct utmpx utx;
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
979*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX
980*7c478bd9Sstevel@tonic-gate 	(void) line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
981*7c478bd9Sstevel@tonic-gate # endif
982*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX
983*7c478bd9Sstevel@tonic-gate 	utx.ut_type = DEAD_PROCESS;
984*7c478bd9Sstevel@tonic-gate # endif
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY
987*7c478bd9Sstevel@tonic-gate 	(void) utmpx_write_library(li, &utx);
988*7c478bd9Sstevel@tonic-gate # else
989*7c478bd9Sstevel@tonic-gate 	utmpx_write_direct(li, &utx);
990*7c478bd9Sstevel@tonic-gate # endif
991*7c478bd9Sstevel@tonic-gate 	return 1;
992*7c478bd9Sstevel@tonic-gate }
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate int
995*7c478bd9Sstevel@tonic-gate utmpx_write_entry(struct logininfo *li)
996*7c478bd9Sstevel@tonic-gate {
997*7c478bd9Sstevel@tonic-gate 	if (li->line_null) {
998*7c478bd9Sstevel@tonic-gate 		debug3("not writing utmpx entry");
999*7c478bd9Sstevel@tonic-gate 		return 1;
1000*7c478bd9Sstevel@tonic-gate 	}
1001*7c478bd9Sstevel@tonic-gate 	debug3("writing utmpx entry");
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	switch(li->type) {
1004*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
1005*7c478bd9Sstevel@tonic-gate 		return utmpx_perform_login(li);
1006*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
1007*7c478bd9Sstevel@tonic-gate 		return utmpx_perform_logout(li);
1008*7c478bd9Sstevel@tonic-gate 	default:
1009*7c478bd9Sstevel@tonic-gate 		log("utmpx_write_entry: invalid type field");
1010*7c478bd9Sstevel@tonic-gate 		return 0;
1011*7c478bd9Sstevel@tonic-gate 	}
1012*7c478bd9Sstevel@tonic-gate }
1013*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX */
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate /**
1017*7c478bd9Sstevel@tonic-gate  ** Low-level wtmp functions
1018*7c478bd9Sstevel@tonic-gate  **/
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMP
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate /* write a wtmp entry direct to the end of the file */
1023*7c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */
1024*7c478bd9Sstevel@tonic-gate static int
1025*7c478bd9Sstevel@tonic-gate wtmp_write(struct logininfo *li, struct utmp *ut)
1026*7c478bd9Sstevel@tonic-gate {
1027*7c478bd9Sstevel@tonic-gate 	struct stat buf;
1028*7c478bd9Sstevel@tonic-gate 	int fd, ret = 1;
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1031*7c478bd9Sstevel@tonic-gate 		log("wtmp_write: problem writing %s: %s",
1032*7c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
1033*7c478bd9Sstevel@tonic-gate 		return 0;
1034*7c478bd9Sstevel@tonic-gate 	}
1035*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == 0)
1036*7c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
1037*7c478bd9Sstevel@tonic-gate 			(void) ftruncate(fd, buf.st_size);
1038*7c478bd9Sstevel@tonic-gate 			log("wtmp_write: problem writing %s: %s",
1039*7c478bd9Sstevel@tonic-gate 			    WTMP_FILE, strerror(errno));
1040*7c478bd9Sstevel@tonic-gate 			ret = 0;
1041*7c478bd9Sstevel@tonic-gate 		}
1042*7c478bd9Sstevel@tonic-gate 	(void)close(fd);
1043*7c478bd9Sstevel@tonic-gate 	return ret;
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate static int
1047*7c478bd9Sstevel@tonic-gate wtmp_perform_login(struct logininfo *li)
1048*7c478bd9Sstevel@tonic-gate {
1049*7c478bd9Sstevel@tonic-gate 	struct utmp ut;
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
1052*7c478bd9Sstevel@tonic-gate 	return wtmp_write(li, &ut);
1053*7c478bd9Sstevel@tonic-gate }
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate static int
1057*7c478bd9Sstevel@tonic-gate wtmp_perform_logout(struct logininfo *li)
1058*7c478bd9Sstevel@tonic-gate {
1059*7c478bd9Sstevel@tonic-gate 	struct utmp ut;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	construct_utmp(li, &ut);
1062*7c478bd9Sstevel@tonic-gate 	return wtmp_write(li, &ut);
1063*7c478bd9Sstevel@tonic-gate }
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate int
1067*7c478bd9Sstevel@tonic-gate wtmp_write_entry(struct logininfo *li)
1068*7c478bd9Sstevel@tonic-gate {
1069*7c478bd9Sstevel@tonic-gate 	switch(li->type) {
1070*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
1071*7c478bd9Sstevel@tonic-gate 		return wtmp_perform_login(li);
1072*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
1073*7c478bd9Sstevel@tonic-gate 		return wtmp_perform_logout(li);
1074*7c478bd9Sstevel@tonic-gate 	default:
1075*7c478bd9Sstevel@tonic-gate 		log("wtmp_write_entry: invalid type field");
1076*7c478bd9Sstevel@tonic-gate 		return 0;
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate }
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate /* Notes on fetching login data from wtmp/wtmpx
1082*7c478bd9Sstevel@tonic-gate  *
1083*7c478bd9Sstevel@tonic-gate  * Logouts are usually recorded with (amongst other things) a blank
1084*7c478bd9Sstevel@tonic-gate  * username on a given tty line.  However, some systems (HP-UX is one)
1085*7c478bd9Sstevel@tonic-gate  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
1086*7c478bd9Sstevel@tonic-gate  *
1087*7c478bd9Sstevel@tonic-gate  * Since we're only looking for logins here, we know that the username
1088*7c478bd9Sstevel@tonic-gate  * must be set correctly. On systems that leave it in, we check for
1089*7c478bd9Sstevel@tonic-gate  * ut_type==USER_PROCESS (indicating a login.)
1090*7c478bd9Sstevel@tonic-gate  *
1091*7c478bd9Sstevel@tonic-gate  * Portability: Some systems may set something other than USER_PROCESS
1092*7c478bd9Sstevel@tonic-gate  * to indicate a login process. I don't know of any as I write. Also,
1093*7c478bd9Sstevel@tonic-gate  * it's possible that some systems may both leave the username in
1094*7c478bd9Sstevel@tonic-gate  * place and not have ut_type.
1095*7c478bd9Sstevel@tonic-gate  */
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate /* return true if this wtmp entry indicates a login */
1098*7c478bd9Sstevel@tonic-gate static int
1099*7c478bd9Sstevel@tonic-gate wtmp_islogin(struct logininfo *li, struct utmp *ut)
1100*7c478bd9Sstevel@tonic-gate {
1101*7c478bd9Sstevel@tonic-gate 	if (strncmp(li->username, ut->ut_name,
1102*7c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
1103*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP
1104*7c478bd9Sstevel@tonic-gate 		if (ut->ut_type & USER_PROCESS)
1105*7c478bd9Sstevel@tonic-gate 			return 1;
1106*7c478bd9Sstevel@tonic-gate # else
1107*7c478bd9Sstevel@tonic-gate 		return 1;
1108*7c478bd9Sstevel@tonic-gate # endif
1109*7c478bd9Sstevel@tonic-gate 	}
1110*7c478bd9Sstevel@tonic-gate 	return 0;
1111*7c478bd9Sstevel@tonic-gate }
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate int
1114*7c478bd9Sstevel@tonic-gate wtmp_get_entry(struct logininfo *li)
1115*7c478bd9Sstevel@tonic-gate {
1116*7c478bd9Sstevel@tonic-gate 	struct stat st;
1117*7c478bd9Sstevel@tonic-gate 	struct utmp ut;
1118*7c478bd9Sstevel@tonic-gate 	int fd, found=0;
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	/* Clear the time entries in our logininfo */
1121*7c478bd9Sstevel@tonic-gate 	li->tv_sec = li->tv_usec = 0;
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1124*7c478bd9Sstevel@tonic-gate 		log("wtmp_get_entry: problem opening %s: %s",
1125*7c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
1126*7c478bd9Sstevel@tonic-gate 		return 0;
1127*7c478bd9Sstevel@tonic-gate 	}
1128*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &st) != 0) {
1129*7c478bd9Sstevel@tonic-gate 		log("wtmp_get_entry: couldn't stat %s: %s",
1130*7c478bd9Sstevel@tonic-gate 		    WTMP_FILE, strerror(errno));
1131*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1132*7c478bd9Sstevel@tonic-gate 		return 0;
1133*7c478bd9Sstevel@tonic-gate 	}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	/* Seek to the start of the last struct utmp */
1136*7c478bd9Sstevel@tonic-gate 	if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
1137*7c478bd9Sstevel@tonic-gate 		/* Looks like we've got a fresh wtmp file */
1138*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1139*7c478bd9Sstevel@tonic-gate 		return 0;
1140*7c478bd9Sstevel@tonic-gate 	}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	while (!found) {
1143*7c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
1144*7c478bd9Sstevel@tonic-gate 			log("wtmp_get_entry: read of %s failed: %s",
1145*7c478bd9Sstevel@tonic-gate 			    WTMP_FILE, strerror(errno));
1146*7c478bd9Sstevel@tonic-gate 			(void) close (fd);
1147*7c478bd9Sstevel@tonic-gate 			return 0;
1148*7c478bd9Sstevel@tonic-gate 		}
1149*7c478bd9Sstevel@tonic-gate 		if ( wtmp_islogin(li, &ut) ) {
1150*7c478bd9Sstevel@tonic-gate 			found = 1;
1151*7c478bd9Sstevel@tonic-gate 			/* We've already checked for a time in struct
1152*7c478bd9Sstevel@tonic-gate 			 * utmp, in login_getlast(). */
1153*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMP
1154*7c478bd9Sstevel@tonic-gate 			li->tv_sec = ut.ut_time;
1155*7c478bd9Sstevel@tonic-gate # else
1156*7c478bd9Sstevel@tonic-gate #  if HAVE_TV_IN_UTMP
1157*7c478bd9Sstevel@tonic-gate 			li->tv_sec = ut.ut_tv.tv_sec;
1158*7c478bd9Sstevel@tonic-gate #  endif
1159*7c478bd9Sstevel@tonic-gate # endif
1160*7c478bd9Sstevel@tonic-gate 			(void) line_fullname(li->line, ut.ut_line,
1161*7c478bd9Sstevel@tonic-gate 				      MIN_SIZEOF(li->line, ut.ut_line));
1162*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP
1163*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(li->hostname, ut.ut_host,
1164*7c478bd9Sstevel@tonic-gate 				MIN_SIZEOF(li->hostname, ut.ut_host));
1165*7c478bd9Sstevel@tonic-gate # endif
1166*7c478bd9Sstevel@tonic-gate 			continue;
1167*7c478bd9Sstevel@tonic-gate 		}
1168*7c478bd9Sstevel@tonic-gate 		/* Seek back 2 x struct utmp */
1169*7c478bd9Sstevel@tonic-gate 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
1170*7c478bd9Sstevel@tonic-gate 			/* We've found the start of the file, so quit */
1171*7c478bd9Sstevel@tonic-gate 			(void) close (fd);
1172*7c478bd9Sstevel@tonic-gate 			return 0;
1173*7c478bd9Sstevel@tonic-gate 		}
1174*7c478bd9Sstevel@tonic-gate 	}
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate 	/* We found an entry. Tidy up and return */
1177*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1178*7c478bd9Sstevel@tonic-gate 	return 1;
1179*7c478bd9Sstevel@tonic-gate }
1180*7c478bd9Sstevel@tonic-gate # endif /* USE_WTMP */
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate /**
1184*7c478bd9Sstevel@tonic-gate  ** Low-level wtmpx functions
1185*7c478bd9Sstevel@tonic-gate  **/
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX
1188*7c478bd9Sstevel@tonic-gate /* write a wtmpx entry direct to the end of the file */
1189*7c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */
1190*7c478bd9Sstevel@tonic-gate static int
1191*7c478bd9Sstevel@tonic-gate wtmpx_write(struct logininfo *li, struct utmpx *utx)
1192*7c478bd9Sstevel@tonic-gate {
1193*7c478bd9Sstevel@tonic-gate 	struct stat buf;
1194*7c478bd9Sstevel@tonic-gate 	int fd, ret = 1;
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1197*7c478bd9Sstevel@tonic-gate 		log("wtmpx_write: problem opening %s: %s",
1198*7c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
1199*7c478bd9Sstevel@tonic-gate 		return 0;
1200*7c478bd9Sstevel@tonic-gate 	}
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == 0)
1203*7c478bd9Sstevel@tonic-gate 		if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
1204*7c478bd9Sstevel@tonic-gate 			(void) ftruncate(fd, buf.st_size);
1205*7c478bd9Sstevel@tonic-gate 			log("wtmpx_write: problem writing %s: %s",
1206*7c478bd9Sstevel@tonic-gate 			    WTMPX_FILE, strerror(errno));
1207*7c478bd9Sstevel@tonic-gate 			ret = 0;
1208*7c478bd9Sstevel@tonic-gate 		}
1209*7c478bd9Sstevel@tonic-gate 	(void)close(fd);
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 	return ret;
1212*7c478bd9Sstevel@tonic-gate }
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate static int
1216*7c478bd9Sstevel@tonic-gate wtmpx_perform_login(struct logininfo *li)
1217*7c478bd9Sstevel@tonic-gate {
1218*7c478bd9Sstevel@tonic-gate 	struct utmpx utx;
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
1221*7c478bd9Sstevel@tonic-gate 	return wtmpx_write(li, &utx);
1222*7c478bd9Sstevel@tonic-gate }
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate static int
1226*7c478bd9Sstevel@tonic-gate wtmpx_perform_logout(struct logininfo *li)
1227*7c478bd9Sstevel@tonic-gate {
1228*7c478bd9Sstevel@tonic-gate 	struct utmpx utx;
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	construct_utmpx(li, &utx);
1231*7c478bd9Sstevel@tonic-gate 	return wtmpx_write(li, &utx);
1232*7c478bd9Sstevel@tonic-gate }
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate int
1236*7c478bd9Sstevel@tonic-gate wtmpx_write_entry(struct logininfo *li)
1237*7c478bd9Sstevel@tonic-gate {
1238*7c478bd9Sstevel@tonic-gate 	switch(li->type) {
1239*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
1240*7c478bd9Sstevel@tonic-gate 		return wtmpx_perform_login(li);
1241*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
1242*7c478bd9Sstevel@tonic-gate 		return wtmpx_perform_logout(li);
1243*7c478bd9Sstevel@tonic-gate 	default:
1244*7c478bd9Sstevel@tonic-gate 		log("wtmpx_write_entry: invalid type field");
1245*7c478bd9Sstevel@tonic-gate 		return 0;
1246*7c478bd9Sstevel@tonic-gate 	}
1247*7c478bd9Sstevel@tonic-gate }
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate /* Please see the notes above wtmp_islogin() for information about the
1250*7c478bd9Sstevel@tonic-gate    next two functions */
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate /* Return true if this wtmpx entry indicates a login */
1253*7c478bd9Sstevel@tonic-gate static int
1254*7c478bd9Sstevel@tonic-gate wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1255*7c478bd9Sstevel@tonic-gate {
1256*7c478bd9Sstevel@tonic-gate 	if ( strncmp(li->username, utx->ut_name,
1257*7c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
1258*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX
1259*7c478bd9Sstevel@tonic-gate 		if (utx->ut_type == USER_PROCESS)
1260*7c478bd9Sstevel@tonic-gate 			return 1;
1261*7c478bd9Sstevel@tonic-gate # else
1262*7c478bd9Sstevel@tonic-gate 		return 1;
1263*7c478bd9Sstevel@tonic-gate # endif
1264*7c478bd9Sstevel@tonic-gate 	}
1265*7c478bd9Sstevel@tonic-gate 	return 0;
1266*7c478bd9Sstevel@tonic-gate }
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate #if 0
1270*7c478bd9Sstevel@tonic-gate int
1271*7c478bd9Sstevel@tonic-gate wtmpx_get_entry(struct logininfo *li)
1272*7c478bd9Sstevel@tonic-gate {
1273*7c478bd9Sstevel@tonic-gate 	struct stat st;
1274*7c478bd9Sstevel@tonic-gate 	struct utmpx utx;
1275*7c478bd9Sstevel@tonic-gate 	int fd, found=0;
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	/* Clear the time entries */
1278*7c478bd9Sstevel@tonic-gate 	li->tv_sec = li->tv_usec = 0;
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1281*7c478bd9Sstevel@tonic-gate 		log("wtmpx_get_entry: problem opening %s: %s",
1282*7c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
1283*7c478bd9Sstevel@tonic-gate 		return 0;
1284*7c478bd9Sstevel@tonic-gate 	}
1285*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &st) != 0) {
1286*7c478bd9Sstevel@tonic-gate 		log("wtmpx_get_entry: couldn't stat %s: %s",
1287*7c478bd9Sstevel@tonic-gate 		    WTMPX_FILE, strerror(errno));
1288*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1289*7c478bd9Sstevel@tonic-gate 		return 0;
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	/* Seek to the start of the last struct utmpx */
1293*7c478bd9Sstevel@tonic-gate 	if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
1294*7c478bd9Sstevel@tonic-gate 		/* probably a newly rotated wtmpx file */
1295*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1296*7c478bd9Sstevel@tonic-gate 		return 0;
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	while (!found) {
1300*7c478bd9Sstevel@tonic-gate 		if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
1301*7c478bd9Sstevel@tonic-gate 			log("wtmpx_get_entry: read of %s failed: %s",
1302*7c478bd9Sstevel@tonic-gate 			    WTMPX_FILE, strerror(errno));
1303*7c478bd9Sstevel@tonic-gate 			(void) close (fd);
1304*7c478bd9Sstevel@tonic-gate 			return 0;
1305*7c478bd9Sstevel@tonic-gate 		}
1306*7c478bd9Sstevel@tonic-gate 		/* Logouts are recorded as a blank username on a particular line.
1307*7c478bd9Sstevel@tonic-gate 		 * So, we just need to find the username in struct utmpx */
1308*7c478bd9Sstevel@tonic-gate 		if ( wtmpx_islogin(li, &utx) ) {
1309*7c478bd9Sstevel@tonic-gate 			found = 1;
1310*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX
1311*7c478bd9Sstevel@tonic-gate 			li->tv_sec = utx.ut_tv.tv_sec;
1312*7c478bd9Sstevel@tonic-gate # else
1313*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_TIME_IN_UTMPX
1314*7c478bd9Sstevel@tonic-gate 			li->tv_sec = utx.ut_time;
1315*7c478bd9Sstevel@tonic-gate #  endif
1316*7c478bd9Sstevel@tonic-gate # endif
1317*7c478bd9Sstevel@tonic-gate 			(void) line_fullname(li->line, utx.ut_line, sizeof(li->line));
1318*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX
1319*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(li->hostname, utx.ut_host,
1320*7c478bd9Sstevel@tonic-gate 				MIN_SIZEOF(li->hostname, utx.ut_host));
1321*7c478bd9Sstevel@tonic-gate # endif
1322*7c478bd9Sstevel@tonic-gate 			continue;
1323*7c478bd9Sstevel@tonic-gate 		}
1324*7c478bd9Sstevel@tonic-gate 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
1325*7c478bd9Sstevel@tonic-gate 			(void) close (fd);
1326*7c478bd9Sstevel@tonic-gate 			return 0;
1327*7c478bd9Sstevel@tonic-gate 		}
1328*7c478bd9Sstevel@tonic-gate 	}
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1331*7c478bd9Sstevel@tonic-gate 	return 1;
1332*7c478bd9Sstevel@tonic-gate }
1333*7c478bd9Sstevel@tonic-gate #endif
1334*7c478bd9Sstevel@tonic-gate #endif /* USE_WTMPX */
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate /**
1337*7c478bd9Sstevel@tonic-gate  ** Low-level libutil login() functions
1338*7c478bd9Sstevel@tonic-gate  **/
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN
1341*7c478bd9Sstevel@tonic-gate static int
1342*7c478bd9Sstevel@tonic-gate syslogin_perform_login(struct logininfo *li)
1343*7c478bd9Sstevel@tonic-gate {
1344*7c478bd9Sstevel@tonic-gate 	struct utmp *ut;
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
1347*7c478bd9Sstevel@tonic-gate 		log("syslogin_perform_login: couldn't malloc()");
1348*7c478bd9Sstevel@tonic-gate 		return 0;
1349*7c478bd9Sstevel@tonic-gate 	}
1350*7c478bd9Sstevel@tonic-gate 	construct_utmp(li, ut);
1351*7c478bd9Sstevel@tonic-gate 	login(ut);
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 	return 1;
1354*7c478bd9Sstevel@tonic-gate }
1355*7c478bd9Sstevel@tonic-gate 
1356*7c478bd9Sstevel@tonic-gate static int
1357*7c478bd9Sstevel@tonic-gate syslogin_perform_logout(struct logininfo *li)
1358*7c478bd9Sstevel@tonic-gate {
1359*7c478bd9Sstevel@tonic-gate # ifdef HAVE_LOGOUT
1360*7c478bd9Sstevel@tonic-gate 	char line[8];
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	(void)line_stripname(line, li->line, sizeof(line));
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	if (!logout(line)) {
1365*7c478bd9Sstevel@tonic-gate 		log("syslogin_perform_logout: logout() returned an error");
1366*7c478bd9Sstevel@tonic-gate #  ifdef HAVE_LOGWTMP
1367*7c478bd9Sstevel@tonic-gate 	} else {
1368*7c478bd9Sstevel@tonic-gate 		logwtmp(line, "", "");
1369*7c478bd9Sstevel@tonic-gate #  endif
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 	/* FIXME: (ATL - if the need arises) What to do if we have
1372*7c478bd9Sstevel@tonic-gate 	 * login, but no logout?  what if logout but no logwtmp? All
1373*7c478bd9Sstevel@tonic-gate 	 * routines are in libutil so they should all be there,
1374*7c478bd9Sstevel@tonic-gate 	 * but... */
1375*7c478bd9Sstevel@tonic-gate # endif
1376*7c478bd9Sstevel@tonic-gate 	return 1;
1377*7c478bd9Sstevel@tonic-gate }
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate int
1380*7c478bd9Sstevel@tonic-gate syslogin_write_entry(struct logininfo *li)
1381*7c478bd9Sstevel@tonic-gate {
1382*7c478bd9Sstevel@tonic-gate 	switch (li->type) {
1383*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
1384*7c478bd9Sstevel@tonic-gate 		return syslogin_perform_login(li);
1385*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGOUT:
1386*7c478bd9Sstevel@tonic-gate 		return syslogin_perform_logout(li);
1387*7c478bd9Sstevel@tonic-gate 	default:
1388*7c478bd9Sstevel@tonic-gate 		log("syslogin_write_entry: Invalid type field");
1389*7c478bd9Sstevel@tonic-gate 		return 0;
1390*7c478bd9Sstevel@tonic-gate 	}
1391*7c478bd9Sstevel@tonic-gate }
1392*7c478bd9Sstevel@tonic-gate #endif /* USE_LOGIN */
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate /* end of file log-syslogin.c */
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate /**
1397*7c478bd9Sstevel@tonic-gate  ** Low-level lastlog functions
1398*7c478bd9Sstevel@tonic-gate  **/
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG
1401*7c478bd9Sstevel@tonic-gate #define LL_FILE 1
1402*7c478bd9Sstevel@tonic-gate #define LL_DIR 2
1403*7c478bd9Sstevel@tonic-gate #define LL_OTHER 3
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate static void
1406*7c478bd9Sstevel@tonic-gate lastlog_construct(struct logininfo *li, struct lastlog *last)
1407*7c478bd9Sstevel@tonic-gate {
1408*7c478bd9Sstevel@tonic-gate 	/* clear the structure */
1409*7c478bd9Sstevel@tonic-gate 	(void) memset(last, '\0', sizeof(*last));
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 	(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
1412*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(last->ll_host, li->hostname,
1413*7c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(last->ll_host, li->hostname));
1414*7c478bd9Sstevel@tonic-gate 	last->ll_time = li->tv_sec;
1415*7c478bd9Sstevel@tonic-gate }
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate static int
1418*7c478bd9Sstevel@tonic-gate lastlog_filetype(char *filename)
1419*7c478bd9Sstevel@tonic-gate {
1420*7c478bd9Sstevel@tonic-gate 	struct stat st;
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	if (stat(LASTLOG_FILE, &st) != 0) {
1423*7c478bd9Sstevel@tonic-gate 		log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
1424*7c478bd9Sstevel@tonic-gate 			strerror(errno));
1425*7c478bd9Sstevel@tonic-gate 		return 0;
1426*7c478bd9Sstevel@tonic-gate 	}
1427*7c478bd9Sstevel@tonic-gate 	if (S_ISDIR(st.st_mode))
1428*7c478bd9Sstevel@tonic-gate 		return LL_DIR;
1429*7c478bd9Sstevel@tonic-gate 	else if (S_ISREG(st.st_mode))
1430*7c478bd9Sstevel@tonic-gate 		return LL_FILE;
1431*7c478bd9Sstevel@tonic-gate 	else
1432*7c478bd9Sstevel@tonic-gate 		return LL_OTHER;
1433*7c478bd9Sstevel@tonic-gate }
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate /* open the file (using filemode) and seek to the login entry */
1437*7c478bd9Sstevel@tonic-gate static int
1438*7c478bd9Sstevel@tonic-gate lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1439*7c478bd9Sstevel@tonic-gate {
1440*7c478bd9Sstevel@tonic-gate 	off_t offset;
1441*7c478bd9Sstevel@tonic-gate 	int type;
1442*7c478bd9Sstevel@tonic-gate 	char lastlog_file[1024];
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 	type = lastlog_filetype(LASTLOG_FILE);
1445*7c478bd9Sstevel@tonic-gate 	switch (type) {
1446*7c478bd9Sstevel@tonic-gate 		case LL_FILE:
1447*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1448*7c478bd9Sstevel@tonic-gate 			break;
1449*7c478bd9Sstevel@tonic-gate 		case LL_DIR:
1450*7c478bd9Sstevel@tonic-gate 			(void) snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1451*7c478bd9Sstevel@tonic-gate 				 LASTLOG_FILE, li->username);
1452*7c478bd9Sstevel@tonic-gate 			break;
1453*7c478bd9Sstevel@tonic-gate 		default:
1454*7c478bd9Sstevel@tonic-gate 			log("lastlog_openseek: %.100s is not a file or directory!",
1455*7c478bd9Sstevel@tonic-gate 			    LASTLOG_FILE);
1456*7c478bd9Sstevel@tonic-gate 			return 0;
1457*7c478bd9Sstevel@tonic-gate 	}
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate 	*fd = open(lastlog_file, filemode);
1460*7c478bd9Sstevel@tonic-gate 	if ( *fd < 0) {
1461*7c478bd9Sstevel@tonic-gate 		debug("lastlog_openseek: Couldn't open %s: %s",
1462*7c478bd9Sstevel@tonic-gate 		    lastlog_file, strerror(errno));
1463*7c478bd9Sstevel@tonic-gate 		return 0;
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	if (type == LL_FILE) {
1467*7c478bd9Sstevel@tonic-gate 		/* find this uid's offset in the lastlog file */
1468*7c478bd9Sstevel@tonic-gate 		offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 		if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1471*7c478bd9Sstevel@tonic-gate 			log("lastlog_openseek: %s->lseek(): %s",
1472*7c478bd9Sstevel@tonic-gate 			 lastlog_file, strerror(errno));
1473*7c478bd9Sstevel@tonic-gate 			return 0;
1474*7c478bd9Sstevel@tonic-gate 		}
1475*7c478bd9Sstevel@tonic-gate 	}
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 	return 1;
1478*7c478bd9Sstevel@tonic-gate }
1479*7c478bd9Sstevel@tonic-gate 
1480*7c478bd9Sstevel@tonic-gate static int
1481*7c478bd9Sstevel@tonic-gate lastlog_perform_login(struct logininfo *li)
1482*7c478bd9Sstevel@tonic-gate {
1483*7c478bd9Sstevel@tonic-gate 	struct lastlog last;
1484*7c478bd9Sstevel@tonic-gate 	int fd;
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate 	/* create our struct lastlog */
1487*7c478bd9Sstevel@tonic-gate 	lastlog_construct(li, &last);
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 	if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
1490*7c478bd9Sstevel@tonic-gate 		return(0);
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	/* write the entry */
1493*7c478bd9Sstevel@tonic-gate 	if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
1494*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1495*7c478bd9Sstevel@tonic-gate 		log("lastlog_write_filemode: Error writing to %s: %s",
1496*7c478bd9Sstevel@tonic-gate 		    LASTLOG_FILE, strerror(errno));
1497*7c478bd9Sstevel@tonic-gate 		return 0;
1498*7c478bd9Sstevel@tonic-gate 	}
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1501*7c478bd9Sstevel@tonic-gate 	return 1;
1502*7c478bd9Sstevel@tonic-gate }
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate int
1505*7c478bd9Sstevel@tonic-gate lastlog_write_entry(struct logininfo *li)
1506*7c478bd9Sstevel@tonic-gate {
1507*7c478bd9Sstevel@tonic-gate 	switch(li->type) {
1508*7c478bd9Sstevel@tonic-gate 	case LTYPE_LOGIN:
1509*7c478bd9Sstevel@tonic-gate 		return lastlog_perform_login(li);
1510*7c478bd9Sstevel@tonic-gate 	default:
1511*7c478bd9Sstevel@tonic-gate 		log("lastlog_write_entry: Invalid type field");
1512*7c478bd9Sstevel@tonic-gate 		return 0;
1513*7c478bd9Sstevel@tonic-gate 	}
1514*7c478bd9Sstevel@tonic-gate }
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate static void
1517*7c478bd9Sstevel@tonic-gate lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1518*7c478bd9Sstevel@tonic-gate {
1519*7c478bd9Sstevel@tonic-gate 	(void) line_fullname(li->line, last->ll_line, sizeof(li->line));
1520*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(li->hostname, last->ll_host,
1521*7c478bd9Sstevel@tonic-gate 		MIN_SIZEOF(li->hostname, last->ll_host));
1522*7c478bd9Sstevel@tonic-gate 	li->tv_sec = last->ll_time;
1523*7c478bd9Sstevel@tonic-gate }
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate int
1526*7c478bd9Sstevel@tonic-gate lastlog_get_entry(struct logininfo *li)
1527*7c478bd9Sstevel@tonic-gate {
1528*7c478bd9Sstevel@tonic-gate 	struct lastlog last;
1529*7c478bd9Sstevel@tonic-gate 	int fd;
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	if (!lastlog_openseek(li, &fd, O_RDONLY))
1532*7c478bd9Sstevel@tonic-gate 		return 0;
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate 	if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
1535*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1536*7c478bd9Sstevel@tonic-gate 		log("lastlog_get_entry: Error reading from %s: %s",
1537*7c478bd9Sstevel@tonic-gate 		    LASTLOG_FILE, strerror(errno));
1538*7c478bd9Sstevel@tonic-gate 		return 0;
1539*7c478bd9Sstevel@tonic-gate 	}
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	lastlog_populate_entry(li, &last);
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate 	return 1;
1546*7c478bd9Sstevel@tonic-gate }
1547*7c478bd9Sstevel@tonic-gate #endif /* USE_LASTLOG */
1548