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