xref: /freebsd/crypto/openssh/loginrec.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
183d2307dSDag-Erling Smørgrav /*
283d2307dSDag-Erling Smørgrav  * Copyright (c) 2000 Andre Lucas.  All rights reserved.
383d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1998 Todd C. Miller
483d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1996 Jason Downs
583d2307dSDag-Erling Smørgrav  * Portions copyright (c) 1996 Theo de Raadt
683d2307dSDag-Erling Smørgrav  *
783d2307dSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
883d2307dSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
983d2307dSDag-Erling Smørgrav  * are met:
1083d2307dSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1183d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1283d2307dSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1383d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1483d2307dSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1583d2307dSDag-Erling Smørgrav  *
1683d2307dSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1783d2307dSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1883d2307dSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1983d2307dSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2083d2307dSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2183d2307dSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2283d2307dSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2383d2307dSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2483d2307dSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2583d2307dSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2683d2307dSDag-Erling Smørgrav  */
2783d2307dSDag-Erling Smørgrav 
28aa49c926SDag-Erling Smørgrav /*
29aa49c926SDag-Erling Smørgrav  * The btmp logging code is derived from login.c from util-linux and is under
30aa49c926SDag-Erling Smørgrav  * the the following license:
31aa49c926SDag-Erling Smørgrav  *
32aa49c926SDag-Erling Smørgrav  * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
33aa49c926SDag-Erling Smørgrav  * All rights reserved.
34aa49c926SDag-Erling Smørgrav  *
35aa49c926SDag-Erling Smørgrav  * Redistribution and use in source and binary forms are permitted
36aa49c926SDag-Erling Smørgrav  * provided that the above copyright notice and this paragraph are
37aa49c926SDag-Erling Smørgrav  * duplicated in all such forms and that any documentation,
38aa49c926SDag-Erling Smørgrav  * advertising materials, and other materials related to such
39aa49c926SDag-Erling Smørgrav  * distribution and use acknowledge that the software was developed
40aa49c926SDag-Erling Smørgrav  * by the University of California, Berkeley.  The name of the
41aa49c926SDag-Erling Smørgrav  * University may not be used to endorse or promote products derived
42aa49c926SDag-Erling Smørgrav  * from this software without specific prior written permission.
43aa49c926SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44aa49c926SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45aa49c926SDag-Erling Smørgrav  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46aa49c926SDag-Erling Smørgrav  */
47aa49c926SDag-Erling Smørgrav 
48aa49c926SDag-Erling Smørgrav 
4983d2307dSDag-Erling Smørgrav /**
5083d2307dSDag-Erling Smørgrav  ** loginrec.c:  platform-independent login recording and lastlog retrieval
5183d2307dSDag-Erling Smørgrav  **/
5283d2307dSDag-Erling Smørgrav 
5383d2307dSDag-Erling Smørgrav /*
54aa49c926SDag-Erling Smørgrav  *  The new login code explained
55aa49c926SDag-Erling Smørgrav  *  ============================
56aa49c926SDag-Erling Smørgrav  *
57aa49c926SDag-Erling Smørgrav  *  This code attempts to provide a common interface to login recording
58aa49c926SDag-Erling Smørgrav  *  (utmp and friends) and last login time retrieval.
59aa49c926SDag-Erling Smørgrav  *
60aa49c926SDag-Erling Smørgrav  *  Its primary means of achieving this is to use 'struct logininfo', a
61aa49c926SDag-Erling Smørgrav  *  union of all the useful fields in the various different types of
62aa49c926SDag-Erling Smørgrav  *  system login record structures one finds on UNIX variants.
63aa49c926SDag-Erling Smørgrav  *
64aa49c926SDag-Erling Smørgrav  *  We depend on autoconf to define which recording methods are to be
65aa49c926SDag-Erling Smørgrav  *  used, and which fields are contained in the relevant data structures
66aa49c926SDag-Erling Smørgrav  *  on the local system. Many C preprocessor symbols affect which code
67aa49c926SDag-Erling Smørgrav  *  gets compiled here.
68aa49c926SDag-Erling Smørgrav  *
69aa49c926SDag-Erling Smørgrav  *  The code is designed to make it easy to modify a particular
70aa49c926SDag-Erling Smørgrav  *  recording method, without affecting other methods nor requiring so
71aa49c926SDag-Erling Smørgrav  *  many nested conditional compilation blocks as were commonplace in
72aa49c926SDag-Erling Smørgrav  *  the old code.
73aa49c926SDag-Erling Smørgrav  *
74aa49c926SDag-Erling Smørgrav  *  For login recording, we try to use the local system's libraries as
75aa49c926SDag-Erling Smørgrav  *  these are clearly most likely to work correctly. For utmp systems
76aa49c926SDag-Erling Smørgrav  *  this usually means login() and logout() or setutent() etc., probably
77aa49c926SDag-Erling Smørgrav  *  in libutil, along with logwtmp() etc. On these systems, we fall back
78aa49c926SDag-Erling Smørgrav  *  to writing the files directly if we have to, though this method
79aa49c926SDag-Erling Smørgrav  *  requires very thorough testing so we do not corrupt local auditing
80aa49c926SDag-Erling Smørgrav  *  information. These files and their access methods are very system
81aa49c926SDag-Erling Smørgrav  *  specific indeed.
82aa49c926SDag-Erling Smørgrav  *
83aa49c926SDag-Erling Smørgrav  *  For utmpx systems, the corresponding library functions are
84aa49c926SDag-Erling Smørgrav  *  setutxent() etc. To the author's knowledge, all utmpx systems have
85aa49c926SDag-Erling Smørgrav  *  these library functions and so no direct write is attempted. If such
86aa49c926SDag-Erling Smørgrav  *  a system exists and needs support, direct analogues of the [uw]tmp
87aa49c926SDag-Erling Smørgrav  *  code should suffice.
88aa49c926SDag-Erling Smørgrav  *
89aa49c926SDag-Erling Smørgrav  *  Retrieving the time of last login ('lastlog') is in some ways even
90aa49c926SDag-Erling Smørgrav  *  more problemmatic than login recording. Some systems provide a
91aa49c926SDag-Erling Smørgrav  *  simple table of all users which we seek based on uid and retrieve a
92aa49c926SDag-Erling Smørgrav  *  relatively standard structure. Others record the same information in
93aa49c926SDag-Erling Smørgrav  *  a directory with a separate file, and others don't record the
94aa49c926SDag-Erling Smørgrav  *  information separately at all. For systems in the latter category,
95aa49c926SDag-Erling Smørgrav  *  we look backwards in the wtmp or wtmpx file for the last login entry
96aa49c926SDag-Erling Smørgrav  *  for our user. Naturally this is slower and on busy systems could
97aa49c926SDag-Erling Smørgrav  *  incur a significant performance penalty.
98aa49c926SDag-Erling Smørgrav  *
99aa49c926SDag-Erling Smørgrav  *  Calling the new code
100aa49c926SDag-Erling Smørgrav  *  --------------------
101aa49c926SDag-Erling Smørgrav  *
102aa49c926SDag-Erling Smørgrav  *  In OpenSSH all login recording and retrieval is performed in
103aa49c926SDag-Erling Smørgrav  *  login.c. Here you'll find working examples. Also, in the logintest.c
104aa49c926SDag-Erling Smørgrav  *  program there are more examples.
105aa49c926SDag-Erling Smørgrav  *
106aa49c926SDag-Erling Smørgrav  *  Internal handler calling method
107aa49c926SDag-Erling Smørgrav  *  -------------------------------
108aa49c926SDag-Erling Smørgrav  *
109aa49c926SDag-Erling Smørgrav  *  When a call is made to login_login() or login_logout(), both
110aa49c926SDag-Erling Smørgrav  *  routines set a struct logininfo flag defining which action (log in,
111aa49c926SDag-Erling Smørgrav  *  or log out) is to be taken. They both then call login_write(), which
112aa49c926SDag-Erling Smørgrav  *  calls whichever of the many structure-specific handlers autoconf
113aa49c926SDag-Erling Smørgrav  *  selects for the local system.
114aa49c926SDag-Erling Smørgrav  *
115aa49c926SDag-Erling Smørgrav  *  The handlers themselves handle system data structure specifics. Both
116aa49c926SDag-Erling Smørgrav  *  struct utmp and struct utmpx have utility functions (see
117aa49c926SDag-Erling Smørgrav  *  construct_utmp*()) to try to make it simpler to add extra systems
118aa49c926SDag-Erling Smørgrav  *  that introduce new features to either structure.
119aa49c926SDag-Erling Smørgrav  *
120aa49c926SDag-Erling Smørgrav  *  While it may seem terribly wasteful to replicate so much similar
121aa49c926SDag-Erling Smørgrav  *  code for each method, experience has shown that maintaining code to
122aa49c926SDag-Erling Smørgrav  *  write both struct utmp and utmpx in one function, whilst maintaining
123aa49c926SDag-Erling Smørgrav  *  support for all systems whether they have library support or not, is
124aa49c926SDag-Erling Smørgrav  *  a difficult and time-consuming task.
125aa49c926SDag-Erling Smørgrav  *
126aa49c926SDag-Erling Smørgrav  *  Lastlog support proceeds similarly. Functions login_get_lastlog()
127aa49c926SDag-Erling Smørgrav  *  (and its OpenSSH-tuned friend login_get_lastlog_time()) call
128aa49c926SDag-Erling Smørgrav  *  getlast_entry(), which tries one of three methods to find the last
129aa49c926SDag-Erling Smørgrav  *  login time. It uses local system lastlog support if it can,
130aa49c926SDag-Erling Smørgrav  *  otherwise it tries wtmp or wtmpx before giving up and returning 0,
131aa49c926SDag-Erling Smørgrav  *  meaning "tilt".
132aa49c926SDag-Erling Smørgrav  *
133aa49c926SDag-Erling Smørgrav  *  Maintenance
134aa49c926SDag-Erling Smørgrav  *  -----------
135aa49c926SDag-Erling Smørgrav  *
136aa49c926SDag-Erling Smørgrav  *  In many cases it's possible to tweak autoconf to select the correct
137aa49c926SDag-Erling Smørgrav  *  methods for a particular platform, either by improving the detection
138aa49c926SDag-Erling Smørgrav  *  code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
139aa49c926SDag-Erling Smørgrav  *  symbols for the platform.
140aa49c926SDag-Erling Smørgrav  *
141aa49c926SDag-Erling Smørgrav  *  Use logintest to check which symbols are defined before modifying
142aa49c926SDag-Erling Smørgrav  *  configure.ac and loginrec.c. (You have to build logintest yourself
143aa49c926SDag-Erling Smørgrav  *  with 'make logintest' as it's not built by default.)
144aa49c926SDag-Erling Smørgrav  *
145aa49c926SDag-Erling Smørgrav  *  Otherwise, patches to the specific method(s) are very helpful!
14683d2307dSDag-Erling Smørgrav  */
14783d2307dSDag-Erling Smørgrav 
14883d2307dSDag-Erling Smørgrav #include "includes.h"
14983d2307dSDag-Erling Smørgrav 
150333ee039SDag-Erling Smørgrav #include <sys/types.h>
151333ee039SDag-Erling Smørgrav #include <sys/stat.h>
152333ee039SDag-Erling Smørgrav #include <sys/socket.h>
153acc1a9efSDag-Erling Smørgrav #ifdef HAVE_SYS_TIME_H
154acc1a9efSDag-Erling Smørgrav # include <sys/time.h>
155acc1a9efSDag-Erling Smørgrav #endif
156333ee039SDag-Erling Smørgrav 
157333ee039SDag-Erling Smørgrav #include <netinet/in.h>
158333ee039SDag-Erling Smørgrav 
15919261079SEd Maste #include <stdlib.h>
160333ee039SDag-Erling Smørgrav #include <errno.h>
161333ee039SDag-Erling Smørgrav #include <fcntl.h>
162333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H
163333ee039SDag-Erling Smørgrav # include <paths.h>
164333ee039SDag-Erling Smørgrav #endif
165333ee039SDag-Erling Smørgrav #include <pwd.h>
166333ee039SDag-Erling Smørgrav #include <stdarg.h>
16719261079SEd Maste #include <stdio.h>
168333ee039SDag-Erling Smørgrav #include <string.h>
169d4af9e69SDag-Erling Smørgrav #include <time.h>
170333ee039SDag-Erling Smørgrav #include <unistd.h>
171333ee039SDag-Erling Smørgrav 
17283d2307dSDag-Erling Smørgrav #include "xmalloc.h"
173190cef3dSDag-Erling Smørgrav #include "sshkey.h"
174333ee039SDag-Erling Smørgrav #include "hostfile.h"
175333ee039SDag-Erling Smørgrav #include "ssh.h"
17683d2307dSDag-Erling Smørgrav #include "loginrec.h"
17783d2307dSDag-Erling Smørgrav #include "log.h"
17883d2307dSDag-Erling Smørgrav #include "atomicio.h"
179aa49c926SDag-Erling Smørgrav #include "packet.h"
180aa49c926SDag-Erling Smørgrav #include "canohost.h"
181aa49c926SDag-Erling Smørgrav #include "auth.h"
182190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
183190cef3dSDag-Erling Smørgrav #include "ssherr.h"
184*1323ec57SEd Maste #include "misc.h"
18583d2307dSDag-Erling Smørgrav 
18683d2307dSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
18783d2307dSDag-Erling Smørgrav # include <util.h>
18883d2307dSDag-Erling Smørgrav #endif
18983d2307dSDag-Erling Smørgrav 
19083d2307dSDag-Erling Smørgrav /**
19183d2307dSDag-Erling Smørgrav  ** prototypes for helper functions in this file
19283d2307dSDag-Erling Smørgrav  **/
19383d2307dSDag-Erling Smørgrav 
19483d2307dSDag-Erling Smørgrav #if HAVE_UTMP_H
19583d2307dSDag-Erling Smørgrav void set_utmp_time(struct logininfo *li, struct utmp *ut);
19683d2307dSDag-Erling Smørgrav void construct_utmp(struct logininfo *li, struct utmp *ut);
19783d2307dSDag-Erling Smørgrav #endif
19883d2307dSDag-Erling Smørgrav 
19983d2307dSDag-Erling Smørgrav #ifdef HAVE_UTMPX_H
20083d2307dSDag-Erling Smørgrav void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
20183d2307dSDag-Erling Smørgrav void construct_utmpx(struct logininfo *li, struct utmpx *ut);
20283d2307dSDag-Erling Smørgrav #endif
20383d2307dSDag-Erling Smørgrav 
20483d2307dSDag-Erling Smørgrav int utmp_write_entry(struct logininfo *li);
20583d2307dSDag-Erling Smørgrav int utmpx_write_entry(struct logininfo *li);
20683d2307dSDag-Erling Smørgrav int wtmp_write_entry(struct logininfo *li);
20783d2307dSDag-Erling Smørgrav int wtmpx_write_entry(struct logininfo *li);
20883d2307dSDag-Erling Smørgrav int lastlog_write_entry(struct logininfo *li);
20983d2307dSDag-Erling Smørgrav int syslogin_write_entry(struct logininfo *li);
21083d2307dSDag-Erling Smørgrav 
21183d2307dSDag-Erling Smørgrav int getlast_entry(struct logininfo *li);
21283d2307dSDag-Erling Smørgrav int lastlog_get_entry(struct logininfo *li);
213b40cdde6SEd Schouten int utmpx_get_entry(struct logininfo *li);
21483d2307dSDag-Erling Smørgrav int wtmp_get_entry(struct logininfo *li);
21583d2307dSDag-Erling Smørgrav int wtmpx_get_entry(struct logininfo *li);
21683d2307dSDag-Erling Smørgrav 
217190cef3dSDag-Erling Smørgrav extern struct sshbuf *loginmsg;
218aa49c926SDag-Erling Smørgrav 
21983d2307dSDag-Erling Smørgrav /* pick the shortest string */
22083d2307dSDag-Erling Smørgrav #define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2))
22183d2307dSDag-Erling Smørgrav 
22283d2307dSDag-Erling Smørgrav /**
22383d2307dSDag-Erling Smørgrav  ** platform-independent login functions
22483d2307dSDag-Erling Smørgrav  **/
22583d2307dSDag-Erling Smørgrav 
226aa49c926SDag-Erling Smørgrav /*
227aa49c926SDag-Erling Smørgrav  * login_login(struct logininfo *) - Record a login
22883d2307dSDag-Erling Smørgrav  *
22983d2307dSDag-Erling Smørgrav  * Call with a pointer to a struct logininfo initialised with
23083d2307dSDag-Erling Smørgrav  * login_init_entry() or login_alloc_entry()
23183d2307dSDag-Erling Smørgrav  *
23283d2307dSDag-Erling Smørgrav  * Returns:
23383d2307dSDag-Erling Smørgrav  *  >0 if successful
23483d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
23583d2307dSDag-Erling Smørgrav  */
23683d2307dSDag-Erling Smørgrav int
login_login(struct logininfo * li)23783d2307dSDag-Erling Smørgrav login_login(struct logininfo *li)
23883d2307dSDag-Erling Smørgrav {
23983d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGIN;
240aa49c926SDag-Erling Smørgrav 	return (login_write(li));
24183d2307dSDag-Erling Smørgrav }
24283d2307dSDag-Erling Smørgrav 
24383d2307dSDag-Erling Smørgrav 
244aa49c926SDag-Erling Smørgrav /*
245aa49c926SDag-Erling Smørgrav  * login_logout(struct logininfo *) - Record a logout
24683d2307dSDag-Erling Smørgrav  *
24783d2307dSDag-Erling Smørgrav  * Call as with login_login()
24883d2307dSDag-Erling Smørgrav  *
24983d2307dSDag-Erling Smørgrav  * Returns:
25083d2307dSDag-Erling Smørgrav  *  >0 if successful
25183d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
25283d2307dSDag-Erling Smørgrav  */
25383d2307dSDag-Erling Smørgrav int
login_logout(struct logininfo * li)25483d2307dSDag-Erling Smørgrav login_logout(struct logininfo *li)
25583d2307dSDag-Erling Smørgrav {
25683d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGOUT;
257aa49c926SDag-Erling Smørgrav 	return (login_write(li));
25883d2307dSDag-Erling Smørgrav }
25983d2307dSDag-Erling Smørgrav 
260aa49c926SDag-Erling Smørgrav /*
261aa49c926SDag-Erling Smørgrav  * login_get_lastlog_time(int) - Retrieve the last login time
26283d2307dSDag-Erling Smørgrav  *
26383d2307dSDag-Erling Smørgrav  * Retrieve the last login time for the given uid. Will try to use the
26483d2307dSDag-Erling Smørgrav  * system lastlog facilities if they are available, but will fall back
26583d2307dSDag-Erling Smørgrav  * to looking in wtmp/wtmpx if necessary
26683d2307dSDag-Erling Smørgrav  *
26783d2307dSDag-Erling Smørgrav  * Returns:
26883d2307dSDag-Erling Smørgrav  *   0 on failure, or if user has never logged in
26983d2307dSDag-Erling Smørgrav  *   Time in seconds from the epoch if successful
27083d2307dSDag-Erling Smørgrav  *
27183d2307dSDag-Erling Smørgrav  * Useful preprocessor symbols:
27283d2307dSDag-Erling Smørgrav  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
27383d2307dSDag-Erling Smørgrav  *                    info
27483d2307dSDag-Erling Smørgrav  *   USE_LASTLOG: If set, indicates the presence of system lastlog
27583d2307dSDag-Erling Smørgrav  *                facilities. If this and DISABLE_LASTLOG are not set,
27683d2307dSDag-Erling Smørgrav  *                try to retrieve lastlog information from wtmp/wtmpx.
27783d2307dSDag-Erling Smørgrav  */
27883d2307dSDag-Erling Smørgrav unsigned int
login_get_lastlog_time(const uid_t uid)2794a421b63SDag-Erling Smørgrav login_get_lastlog_time(const uid_t uid)
28083d2307dSDag-Erling Smørgrav {
28183d2307dSDag-Erling Smørgrav 	struct logininfo li;
28283d2307dSDag-Erling Smørgrav 
28383d2307dSDag-Erling Smørgrav 	if (login_get_lastlog(&li, uid))
284aa49c926SDag-Erling Smørgrav 		return (li.tv_sec);
28583d2307dSDag-Erling Smørgrav 	else
286aa49c926SDag-Erling Smørgrav 		return (0);
28783d2307dSDag-Erling Smørgrav }
28883d2307dSDag-Erling Smørgrav 
289aa49c926SDag-Erling Smørgrav /*
290aa49c926SDag-Erling Smørgrav  * login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
29183d2307dSDag-Erling Smørgrav  *
29283d2307dSDag-Erling Smørgrav  * Retrieve a logininfo structure populated (only partially) with
29383d2307dSDag-Erling Smørgrav  * information from the system lastlog data, or from wtmp/wtmpx if no
29483d2307dSDag-Erling Smørgrav  * system lastlog information exists.
29583d2307dSDag-Erling Smørgrav  *
29683d2307dSDag-Erling Smørgrav  * Note this routine must be given a pre-allocated logininfo.
29783d2307dSDag-Erling Smørgrav  *
29883d2307dSDag-Erling Smørgrav  * Returns:
29983d2307dSDag-Erling Smørgrav  *  >0: A pointer to your struct logininfo if successful
30083d2307dSDag-Erling Smørgrav  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
30183d2307dSDag-Erling Smørgrav  */
30283d2307dSDag-Erling Smørgrav struct logininfo *
login_get_lastlog(struct logininfo * li,const uid_t uid)3034a421b63SDag-Erling Smørgrav login_get_lastlog(struct logininfo *li, const uid_t uid)
30483d2307dSDag-Erling Smørgrav {
30583d2307dSDag-Erling Smørgrav 	struct passwd *pw;
30683d2307dSDag-Erling Smørgrav 
30783d2307dSDag-Erling Smørgrav 	memset(li, '\0', sizeof(*li));
30883d2307dSDag-Erling Smørgrav 	li->uid = uid;
30983d2307dSDag-Erling Smørgrav 
31083d2307dSDag-Erling Smørgrav 	/*
31183d2307dSDag-Erling Smørgrav 	 * If we don't have a 'real' lastlog, we need the username to
31283d2307dSDag-Erling Smørgrav 	 * reliably search wtmp(x) for the last login (see
31383d2307dSDag-Erling Smørgrav 	 * wtmp_get_entry().)
31483d2307dSDag-Erling Smørgrav 	 */
31583d2307dSDag-Erling Smørgrav 	pw = getpwuid(uid);
31683d2307dSDag-Erling Smørgrav 	if (pw == NULL)
3174a421b63SDag-Erling Smørgrav 		fatal("%s: Cannot find account for uid %ld", __func__,
3184a421b63SDag-Erling Smørgrav 		    (long)uid);
31983d2307dSDag-Erling Smørgrav 
320f7167e0eSDag-Erling Smørgrav 	if (strlcpy(li->username, pw->pw_name, sizeof(li->username)) >=
321f7167e0eSDag-Erling Smørgrav 	    sizeof(li->username)) {
322f7167e0eSDag-Erling Smørgrav 		error("%s: username too long (%lu > max %lu)", __func__,
323f7167e0eSDag-Erling Smørgrav 		    (unsigned long)strlen(pw->pw_name),
324f7167e0eSDag-Erling Smørgrav 		    (unsigned long)sizeof(li->username) - 1);
325f7167e0eSDag-Erling Smørgrav 		return NULL;
326f7167e0eSDag-Erling Smørgrav 	}
32783d2307dSDag-Erling Smørgrav 
32883d2307dSDag-Erling Smørgrav 	if (getlast_entry(li))
329aa49c926SDag-Erling Smørgrav 		return (li);
33083d2307dSDag-Erling Smørgrav 	else
331aa49c926SDag-Erling Smørgrav 		return (NULL);
33283d2307dSDag-Erling Smørgrav }
33383d2307dSDag-Erling Smørgrav 
334aa49c926SDag-Erling Smørgrav /*
335aa49c926SDag-Erling Smørgrav  * login_alloc_entry(int, char*, char*, char*)    - Allocate and initialise
33683d2307dSDag-Erling Smørgrav  *                                                  a logininfo structure
33783d2307dSDag-Erling Smørgrav  *
33883d2307dSDag-Erling Smørgrav  * This function creates a new struct logininfo, a data structure
33983d2307dSDag-Erling Smørgrav  * meant to carry the information required to portably record login info.
34083d2307dSDag-Erling Smørgrav  *
34183d2307dSDag-Erling Smørgrav  * Returns a pointer to a newly created struct logininfo. If memory
34283d2307dSDag-Erling Smørgrav  * allocation fails, the program halts.
34383d2307dSDag-Erling Smørgrav  */
34483d2307dSDag-Erling Smørgrav struct
login_alloc_entry(pid_t pid,const char * username,const char * hostname,const char * line)3454a421b63SDag-Erling Smørgrav logininfo *login_alloc_entry(pid_t pid, const char *username,
34683d2307dSDag-Erling Smørgrav     const char *hostname, const char *line)
34783d2307dSDag-Erling Smørgrav {
34883d2307dSDag-Erling Smørgrav 	struct logininfo *newli;
34983d2307dSDag-Erling Smørgrav 
350aa49c926SDag-Erling Smørgrav 	newli = xmalloc(sizeof(*newli));
351aa49c926SDag-Erling Smørgrav 	login_init_entry(newli, pid, username, hostname, line);
352aa49c926SDag-Erling Smørgrav 	return (newli);
35383d2307dSDag-Erling Smørgrav }
35483d2307dSDag-Erling Smørgrav 
35583d2307dSDag-Erling Smørgrav 
35683d2307dSDag-Erling Smørgrav /* login_free_entry(struct logininfo *)    - free struct memory */
35783d2307dSDag-Erling Smørgrav void
login_free_entry(struct logininfo * li)35883d2307dSDag-Erling Smørgrav login_free_entry(struct logininfo *li)
35983d2307dSDag-Erling Smørgrav {
360e4a9863fSDag-Erling Smørgrav 	free(li);
36183d2307dSDag-Erling Smørgrav }
36283d2307dSDag-Erling Smørgrav 
36383d2307dSDag-Erling Smørgrav 
36483d2307dSDag-Erling Smørgrav /* login_init_entry(struct logininfo *, int, char*, char*, char*)
36583d2307dSDag-Erling Smørgrav  *                                        - initialise a struct logininfo
36683d2307dSDag-Erling Smørgrav  *
36783d2307dSDag-Erling Smørgrav  * Populates a new struct logininfo, a data structure meant to carry
36883d2307dSDag-Erling Smørgrav  * the information required to portably record login info.
36983d2307dSDag-Erling Smørgrav  *
37083d2307dSDag-Erling Smørgrav  * Returns: 1
37183d2307dSDag-Erling Smørgrav  */
37283d2307dSDag-Erling Smørgrav int
login_init_entry(struct logininfo * li,pid_t pid,const char * username,const char * hostname,const char * line)3734a421b63SDag-Erling Smørgrav login_init_entry(struct logininfo *li, pid_t pid, const char *username,
37483d2307dSDag-Erling Smørgrav     const char *hostname, const char *line)
37583d2307dSDag-Erling Smørgrav {
37683d2307dSDag-Erling Smørgrav 	struct passwd *pw;
37783d2307dSDag-Erling Smørgrav 
37883d2307dSDag-Erling Smørgrav 	memset(li, 0, sizeof(*li));
37983d2307dSDag-Erling Smørgrav 
38083d2307dSDag-Erling Smørgrav 	li->pid = pid;
38183d2307dSDag-Erling Smørgrav 
38283d2307dSDag-Erling Smørgrav 	/* set the line information */
38383d2307dSDag-Erling Smørgrav 	if (line)
38483d2307dSDag-Erling Smørgrav 		line_fullname(li->line, line, sizeof(li->line));
38583d2307dSDag-Erling Smørgrav 
38683d2307dSDag-Erling Smørgrav 	if (username) {
38783d2307dSDag-Erling Smørgrav 		strlcpy(li->username, username, sizeof(li->username));
38883d2307dSDag-Erling Smørgrav 		pw = getpwnam(li->username);
389aa49c926SDag-Erling Smørgrav 		if (pw == NULL) {
390aa49c926SDag-Erling Smørgrav 			fatal("%s: Cannot find user \"%s\"", __func__,
391aa49c926SDag-Erling Smørgrav 			    li->username);
392aa49c926SDag-Erling Smørgrav 		}
39383d2307dSDag-Erling Smørgrav 		li->uid = pw->pw_uid;
39483d2307dSDag-Erling Smørgrav 	}
39583d2307dSDag-Erling Smørgrav 
39683d2307dSDag-Erling Smørgrav 	if (hostname)
39783d2307dSDag-Erling Smørgrav 		strlcpy(li->hostname, hostname, sizeof(li->hostname));
39883d2307dSDag-Erling Smørgrav 
399aa49c926SDag-Erling Smørgrav 	return (1);
40083d2307dSDag-Erling Smørgrav }
40183d2307dSDag-Erling Smørgrav 
402aa49c926SDag-Erling Smørgrav /*
403aa49c926SDag-Erling Smørgrav  * login_set_current_time(struct logininfo *)    - set the current time
40483d2307dSDag-Erling Smørgrav  *
40583d2307dSDag-Erling Smørgrav  * Set the current time in a logininfo structure. This function is
40683d2307dSDag-Erling Smørgrav  * meant to eliminate the need to deal with system dependencies for
40783d2307dSDag-Erling Smørgrav  * time handling.
40883d2307dSDag-Erling Smørgrav  */
40983d2307dSDag-Erling Smørgrav void
login_set_current_time(struct logininfo * li)41083d2307dSDag-Erling Smørgrav login_set_current_time(struct logininfo *li)
41183d2307dSDag-Erling Smørgrav {
41283d2307dSDag-Erling Smørgrav 	struct timeval tv;
41383d2307dSDag-Erling Smørgrav 
41483d2307dSDag-Erling Smørgrav 	gettimeofday(&tv, NULL);
41583d2307dSDag-Erling Smørgrav 
41683d2307dSDag-Erling Smørgrav 	li->tv_sec = tv.tv_sec;
41783d2307dSDag-Erling Smørgrav 	li->tv_usec = tv.tv_usec;
41883d2307dSDag-Erling Smørgrav }
41983d2307dSDag-Erling Smørgrav 
42083d2307dSDag-Erling Smørgrav /* copy a sockaddr_* into our logininfo */
42183d2307dSDag-Erling Smørgrav void
login_set_addr(struct logininfo * li,const struct sockaddr * sa,const unsigned int sa_size)42283d2307dSDag-Erling Smørgrav login_set_addr(struct logininfo *li, const struct sockaddr *sa,
42383d2307dSDag-Erling Smørgrav     const unsigned int sa_size)
42483d2307dSDag-Erling Smørgrav {
42583d2307dSDag-Erling Smørgrav 	unsigned int bufsize = sa_size;
42683d2307dSDag-Erling Smørgrav 
42783d2307dSDag-Erling Smørgrav 	/* make sure we don't overrun our union */
42883d2307dSDag-Erling Smørgrav 	if (sizeof(li->hostaddr) < sa_size)
42983d2307dSDag-Erling Smørgrav 		bufsize = sizeof(li->hostaddr);
43083d2307dSDag-Erling Smørgrav 
431aa49c926SDag-Erling Smørgrav 	memcpy(&li->hostaddr.sa, sa, bufsize);
43283d2307dSDag-Erling Smørgrav }
43383d2307dSDag-Erling Smørgrav 
43483d2307dSDag-Erling Smørgrav 
43583d2307dSDag-Erling Smørgrav /**
43683d2307dSDag-Erling Smørgrav  ** login_write: Call low-level recording functions based on autoconf
43783d2307dSDag-Erling Smørgrav  ** results
43883d2307dSDag-Erling Smørgrav  **/
43983d2307dSDag-Erling Smørgrav int
login_write(struct logininfo * li)44083d2307dSDag-Erling Smørgrav login_write(struct logininfo *li)
44183d2307dSDag-Erling Smørgrav {
44283d2307dSDag-Erling Smørgrav #ifndef HAVE_CYGWIN
443aa49c926SDag-Erling Smørgrav 	if (geteuid() != 0) {
444cf2b5f3bSDag-Erling Smørgrav 		logit("Attempt to write login records by non-root user (aborting)");
445aa49c926SDag-Erling Smørgrav 		return (1);
44683d2307dSDag-Erling Smørgrav 	}
44783d2307dSDag-Erling Smørgrav #endif
44883d2307dSDag-Erling Smørgrav 
44983d2307dSDag-Erling Smørgrav 	/* set the timestamp */
45083d2307dSDag-Erling Smørgrav 	login_set_current_time(li);
45183d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN
45283d2307dSDag-Erling Smørgrav 	syslogin_write_entry(li);
45383d2307dSDag-Erling Smørgrav #endif
45483d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
455aa49c926SDag-Erling Smørgrav 	if (li->type == LTYPE_LOGIN)
45683d2307dSDag-Erling Smørgrav 		lastlog_write_entry(li);
45783d2307dSDag-Erling Smørgrav #endif
45883d2307dSDag-Erling Smørgrav #ifdef USE_UTMP
45983d2307dSDag-Erling Smørgrav 	utmp_write_entry(li);
46083d2307dSDag-Erling Smørgrav #endif
46183d2307dSDag-Erling Smørgrav #ifdef USE_WTMP
46283d2307dSDag-Erling Smørgrav 	wtmp_write_entry(li);
46383d2307dSDag-Erling Smørgrav #endif
46483d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX
46583d2307dSDag-Erling Smørgrav 	utmpx_write_entry(li);
46683d2307dSDag-Erling Smørgrav #endif
46783d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX
46883d2307dSDag-Erling Smørgrav 	wtmpx_write_entry(li);
46983d2307dSDag-Erling Smørgrav #endif
47021e764dfSDag-Erling Smørgrav #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN
47121e764dfSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGIN &&
472d4ecd108SDag-Erling Smørgrav 	    !sys_auth_record_login(li->username,li->hostname,li->line,
47319261079SEd Maste 	    loginmsg))
47421e764dfSDag-Erling Smørgrav 		logit("Writing login record failed for %s", li->username);
47521e764dfSDag-Erling Smørgrav #endif
476aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS
477aa49c926SDag-Erling Smørgrav 	if (li->type == LTYPE_LOGIN)
4784a421b63SDag-Erling Smørgrav 		audit_session_open(li);
479aa49c926SDag-Erling Smørgrav 	else if (li->type == LTYPE_LOGOUT)
4804a421b63SDag-Erling Smørgrav 		audit_session_close(li);
481aa49c926SDag-Erling Smørgrav #endif
482aa49c926SDag-Erling Smørgrav 	return (0);
48383d2307dSDag-Erling Smørgrav }
48483d2307dSDag-Erling Smørgrav 
48583d2307dSDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
48683d2307dSDag-Erling Smørgrav int
login_utmp_only(struct logininfo * li)48783d2307dSDag-Erling Smørgrav login_utmp_only(struct logininfo *li)
48883d2307dSDag-Erling Smørgrav {
48983d2307dSDag-Erling Smørgrav 	li->type = LTYPE_LOGIN;
49083d2307dSDag-Erling Smørgrav 	login_set_current_time(li);
49183d2307dSDag-Erling Smørgrav # ifdef USE_UTMP
49283d2307dSDag-Erling Smørgrav 	utmp_write_entry(li);
49383d2307dSDag-Erling Smørgrav # endif
49483d2307dSDag-Erling Smørgrav # ifdef USE_WTMP
49583d2307dSDag-Erling Smørgrav 	wtmp_write_entry(li);
49683d2307dSDag-Erling Smørgrav # endif
49783d2307dSDag-Erling Smørgrav # ifdef USE_UTMPX
49883d2307dSDag-Erling Smørgrav 	utmpx_write_entry(li);
49983d2307dSDag-Erling Smørgrav # endif
50083d2307dSDag-Erling Smørgrav # ifdef USE_WTMPX
50183d2307dSDag-Erling Smørgrav 	wtmpx_write_entry(li);
50283d2307dSDag-Erling Smørgrav # endif
503aa49c926SDag-Erling Smørgrav 	return (0);
50483d2307dSDag-Erling Smørgrav }
50583d2307dSDag-Erling Smørgrav #endif
50683d2307dSDag-Erling Smørgrav 
50783d2307dSDag-Erling Smørgrav /**
50883d2307dSDag-Erling Smørgrav  ** getlast_entry: Call low-level functions to retrieve the last login
50983d2307dSDag-Erling Smørgrav  **                time.
51083d2307dSDag-Erling Smørgrav  **/
51183d2307dSDag-Erling Smørgrav 
51283d2307dSDag-Erling Smørgrav /* take the uid in li and return the last login time */
51383d2307dSDag-Erling Smørgrav int
getlast_entry(struct logininfo * li)51483d2307dSDag-Erling Smørgrav getlast_entry(struct logininfo *li)
51583d2307dSDag-Erling Smørgrav {
51683d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
51783d2307dSDag-Erling Smørgrav 	return(lastlog_get_entry(li));
51883d2307dSDag-Erling Smørgrav #else /* !USE_LASTLOG */
5198ad9b54aSDag-Erling Smørgrav #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
5208ad9b54aSDag-Erling Smørgrav     defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
5218ad9b54aSDag-Erling Smørgrav 	return (utmpx_get_entry(li));
5228ad9b54aSDag-Erling Smørgrav #endif
52383d2307dSDag-Erling Smørgrav 
524aa49c926SDag-Erling Smørgrav #if defined(DISABLE_LASTLOG)
52583d2307dSDag-Erling Smørgrav 	/* On some systems we shouldn't even try to obtain last login
52683d2307dSDag-Erling Smørgrav 	 * time, e.g. AIX */
527aa49c926SDag-Erling Smørgrav 	return (0);
528aa49c926SDag-Erling Smørgrav # elif defined(USE_WTMP) && \
529aa49c926SDag-Erling Smørgrav     (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
53083d2307dSDag-Erling Smørgrav 	/* retrieve last login time from utmp */
53183d2307dSDag-Erling Smørgrav 	return (wtmp_get_entry(li));
532aa49c926SDag-Erling Smørgrav # elif defined(USE_WTMPX) && \
533aa49c926SDag-Erling Smørgrav     (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
53483d2307dSDag-Erling Smørgrav 	/* If wtmp isn't available, try wtmpx */
53583d2307dSDag-Erling Smørgrav 	return (wtmpx_get_entry(li));
53683d2307dSDag-Erling Smørgrav # else
53783d2307dSDag-Erling Smørgrav 	/* Give up: No means of retrieving last login time */
538aa49c926SDag-Erling Smørgrav 	return (0);
53983d2307dSDag-Erling Smørgrav # endif /* DISABLE_LASTLOG */
54083d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */
54183d2307dSDag-Erling Smørgrav }
54283d2307dSDag-Erling Smørgrav 
54383d2307dSDag-Erling Smørgrav 
54483d2307dSDag-Erling Smørgrav 
54583d2307dSDag-Erling Smørgrav /*
54683d2307dSDag-Erling Smørgrav  * 'line' string utility functions
54783d2307dSDag-Erling Smørgrav  *
54883d2307dSDag-Erling Smørgrav  * These functions process the 'line' string into one of three forms:
54983d2307dSDag-Erling Smørgrav  *
55083d2307dSDag-Erling Smørgrav  * 1. The full filename (including '/dev')
55183d2307dSDag-Erling Smørgrav  * 2. The stripped name (excluding '/dev')
55283d2307dSDag-Erling Smørgrav  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
55383d2307dSDag-Erling Smørgrav  *                               /dev/pts/1  -> ts/1 )
55483d2307dSDag-Erling Smørgrav  *
55583d2307dSDag-Erling Smørgrav  * Form 3 is used on some systems to identify a .tmp.? entry when
55683d2307dSDag-Erling Smørgrav  * attempting to remove it. Typically both addition and removal is
55783d2307dSDag-Erling Smørgrav  * performed by one application - say, sshd - so as long as the choice
55883d2307dSDag-Erling Smørgrav  * uniquely identifies a terminal it's ok.
55983d2307dSDag-Erling Smørgrav  */
56083d2307dSDag-Erling Smørgrav 
56183d2307dSDag-Erling Smørgrav 
562aa49c926SDag-Erling Smørgrav /*
563aa49c926SDag-Erling Smørgrav  * line_fullname(): add the leading '/dev/' if it doesn't exist make
564aa49c926SDag-Erling Smørgrav  * sure dst has enough space, if not just copy src (ugh)
565aa49c926SDag-Erling Smørgrav  */
56683d2307dSDag-Erling Smørgrav char *
line_fullname(char * dst,const char * src,u_int dstsize)567d4ecd108SDag-Erling Smørgrav line_fullname(char *dst, const char *src, u_int dstsize)
56883d2307dSDag-Erling Smørgrav {
56983d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
570aa49c926SDag-Erling Smørgrav 	if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
57183d2307dSDag-Erling Smørgrav 		strlcpy(dst, src, dstsize);
572aa49c926SDag-Erling Smørgrav 	else {
57383d2307dSDag-Erling Smørgrav 		strlcpy(dst, "/dev/", dstsize);
57483d2307dSDag-Erling Smørgrav 		strlcat(dst, src, dstsize);
57583d2307dSDag-Erling Smørgrav 	}
576aa49c926SDag-Erling Smørgrav 	return (dst);
57783d2307dSDag-Erling Smørgrav }
57883d2307dSDag-Erling Smørgrav 
57983d2307dSDag-Erling Smørgrav /* line_stripname(): strip the leading '/dev' if it exists, return dst */
58083d2307dSDag-Erling Smørgrav char *
line_stripname(char * dst,const char * src,int dstsize)58183d2307dSDag-Erling Smørgrav line_stripname(char *dst, const char *src, int dstsize)
58283d2307dSDag-Erling Smørgrav {
58383d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
58483d2307dSDag-Erling Smørgrav 	if (strncmp(src, "/dev/", 5) == 0)
58583d2307dSDag-Erling Smørgrav 		strlcpy(dst, src + 5, dstsize);
58683d2307dSDag-Erling Smørgrav 	else
58783d2307dSDag-Erling Smørgrav 		strlcpy(dst, src, dstsize);
588aa49c926SDag-Erling Smørgrav 	return (dst);
58983d2307dSDag-Erling Smørgrav }
59083d2307dSDag-Erling Smørgrav 
591aa49c926SDag-Erling Smørgrav /*
592aa49c926SDag-Erling Smørgrav  * line_abbrevname(): Return the abbreviated (usually four-character)
59383d2307dSDag-Erling Smørgrav  * form of the line (Just use the last <dstsize> characters of the
59483d2307dSDag-Erling Smørgrav  * full name.)
59583d2307dSDag-Erling Smørgrav  *
59683d2307dSDag-Erling Smørgrav  * NOTE: use strncpy because we do NOT necessarily want zero
597aa49c926SDag-Erling Smørgrav  * termination
598aa49c926SDag-Erling Smørgrav  */
59983d2307dSDag-Erling Smørgrav char *
line_abbrevname(char * dst,const char * src,int dstsize)60083d2307dSDag-Erling Smørgrav line_abbrevname(char *dst, const char *src, int dstsize)
60183d2307dSDag-Erling Smørgrav {
60283d2307dSDag-Erling Smørgrav 	size_t len;
60383d2307dSDag-Erling Smørgrav 
60483d2307dSDag-Erling Smørgrav 	memset(dst, '\0', dstsize);
60583d2307dSDag-Erling Smørgrav 
60683d2307dSDag-Erling Smørgrav 	/* Always skip prefix if present */
60783d2307dSDag-Erling Smørgrav 	if (strncmp(src, "/dev/", 5) == 0)
60883d2307dSDag-Erling Smørgrav 		src += 5;
60983d2307dSDag-Erling Smørgrav 
61083d2307dSDag-Erling Smørgrav #ifdef WITH_ABBREV_NO_TTY
61183d2307dSDag-Erling Smørgrav 	if (strncmp(src, "tty", 3) == 0)
61283d2307dSDag-Erling Smørgrav 		src += 3;
61383d2307dSDag-Erling Smørgrav #endif
61483d2307dSDag-Erling Smørgrav 
61583d2307dSDag-Erling Smørgrav 	len = strlen(src);
61683d2307dSDag-Erling Smørgrav 
61783d2307dSDag-Erling Smørgrav 	if (len > 0) {
61883d2307dSDag-Erling Smørgrav 		if (((int)len - dstsize) > 0)
61983d2307dSDag-Erling Smørgrav 			src +=  ((int)len - dstsize);
62083d2307dSDag-Erling Smørgrav 
62183d2307dSDag-Erling Smørgrav 		/* note: _don't_ change this to strlcpy */
62283d2307dSDag-Erling Smørgrav 		strncpy(dst, src, (size_t)dstsize);
62383d2307dSDag-Erling Smørgrav 	}
62483d2307dSDag-Erling Smørgrav 
625aa49c926SDag-Erling Smørgrav 	return (dst);
62683d2307dSDag-Erling Smørgrav }
62783d2307dSDag-Erling Smørgrav 
62883d2307dSDag-Erling Smørgrav /**
62983d2307dSDag-Erling Smørgrav  ** utmp utility functions
63083d2307dSDag-Erling Smørgrav  **
63183d2307dSDag-Erling Smørgrav  ** These functions manipulate struct utmp, taking system differences
63283d2307dSDag-Erling Smørgrav  ** into account.
63383d2307dSDag-Erling Smørgrav  **/
63483d2307dSDag-Erling Smørgrav 
63583d2307dSDag-Erling Smørgrav #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
63683d2307dSDag-Erling Smørgrav 
63783d2307dSDag-Erling Smørgrav /* build the utmp structure */
63883d2307dSDag-Erling Smørgrav void
set_utmp_time(struct logininfo * li,struct utmp * ut)63983d2307dSDag-Erling Smørgrav set_utmp_time(struct logininfo *li, struct utmp *ut)
64083d2307dSDag-Erling Smørgrav {
641aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMP)
64283d2307dSDag-Erling Smørgrav 	ut->ut_tv.tv_sec = li->tv_sec;
64383d2307dSDag-Erling Smørgrav 	ut->ut_tv.tv_usec = li->tv_usec;
644aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMP)
64583d2307dSDag-Erling Smørgrav 	ut->ut_time = li->tv_sec;
64683d2307dSDag-Erling Smørgrav # endif
64783d2307dSDag-Erling Smørgrav }
64883d2307dSDag-Erling Smørgrav 
64983d2307dSDag-Erling Smørgrav void
construct_utmp(struct logininfo * li,struct utmp * ut)65083d2307dSDag-Erling Smørgrav construct_utmp(struct logininfo *li,
65183d2307dSDag-Erling Smørgrav 		    struct utmp *ut)
65283d2307dSDag-Erling Smørgrav {
653e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
654e73e9afaSDag-Erling Smørgrav 	struct sockaddr_in6 *sa6;
655e73e9afaSDag-Erling Smørgrav # endif
656aa49c926SDag-Erling Smørgrav 
65783d2307dSDag-Erling Smørgrav 	memset(ut, '\0', sizeof(*ut));
65883d2307dSDag-Erling Smørgrav 
65983d2307dSDag-Erling Smørgrav 	/* First fill out fields used for both logins and logouts */
66083d2307dSDag-Erling Smørgrav 
66183d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMP
66283d2307dSDag-Erling Smørgrav 	line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
66383d2307dSDag-Erling Smørgrav # endif
66483d2307dSDag-Erling Smørgrav 
66583d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP
66683d2307dSDag-Erling Smørgrav 	/* This is done here to keep utmp constants out of struct logininfo */
66783d2307dSDag-Erling Smørgrav 	switch (li->type) {
66883d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
66983d2307dSDag-Erling Smørgrav 		ut->ut_type = USER_PROCESS;
67083d2307dSDag-Erling Smørgrav 		break;
67183d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
67283d2307dSDag-Erling Smørgrav 		ut->ut_type = DEAD_PROCESS;
67383d2307dSDag-Erling Smørgrav 		break;
67483d2307dSDag-Erling Smørgrav 	}
67583d2307dSDag-Erling Smørgrav # endif
67683d2307dSDag-Erling Smørgrav 	set_utmp_time(li, ut);
67783d2307dSDag-Erling Smørgrav 
67883d2307dSDag-Erling Smørgrav 	line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
67983d2307dSDag-Erling Smørgrav 
68083d2307dSDag-Erling Smørgrav # ifdef HAVE_PID_IN_UTMP
68183d2307dSDag-Erling Smørgrav 	ut->ut_pid = li->pid;
68283d2307dSDag-Erling Smørgrav # endif
68383d2307dSDag-Erling Smørgrav 
68483d2307dSDag-Erling Smørgrav 	/* If we're logging out, leave all other fields blank */
68583d2307dSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGOUT)
68683d2307dSDag-Erling Smørgrav 		return;
68783d2307dSDag-Erling Smørgrav 
68883d2307dSDag-Erling Smørgrav 	/*
68983d2307dSDag-Erling Smørgrav 	 * These fields are only used when logging in, and are blank
69083d2307dSDag-Erling Smørgrav 	 * for logouts.
69183d2307dSDag-Erling Smørgrav 	 */
69283d2307dSDag-Erling Smørgrav 
69383d2307dSDag-Erling Smørgrav 	/* Use strncpy because we don't necessarily want null termination */
694aa49c926SDag-Erling Smørgrav 	strncpy(ut->ut_name, li->username,
695aa49c926SDag-Erling Smørgrav 	    MIN_SIZEOF(ut->ut_name, li->username));
69683d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP
6970aeb000dSDag-Erling Smørgrav 	strncpy(ut->ut_host, li->hostname,
6980aeb000dSDag-Erling Smørgrav 	    MIN_SIZEOF(ut->ut_host, li->hostname));
69983d2307dSDag-Erling Smørgrav # endif
70083d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMP
70183d2307dSDag-Erling Smørgrav 	/* this is just a 32-bit IP address */
70283d2307dSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET)
70383d2307dSDag-Erling Smørgrav 		ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
70483d2307dSDag-Erling Smørgrav # endif
705e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
706e73e9afaSDag-Erling Smørgrav 	/* this is just a 128-bit IPv6 address */
707e73e9afaSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET6) {
708e73e9afaSDag-Erling Smørgrav 		sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
709e73e9afaSDag-Erling Smørgrav 		memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
710e73e9afaSDag-Erling Smørgrav 		if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
711e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
712e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[1] = 0;
713e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[2] = 0;
714e73e9afaSDag-Erling Smørgrav 			ut->ut_addr_v6[3] = 0;
715e73e9afaSDag-Erling Smørgrav 		}
716e73e9afaSDag-Erling Smørgrav 	}
717e73e9afaSDag-Erling Smørgrav # endif
71883d2307dSDag-Erling Smørgrav }
71983d2307dSDag-Erling Smørgrav #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
72083d2307dSDag-Erling Smørgrav 
72183d2307dSDag-Erling Smørgrav /**
72283d2307dSDag-Erling Smørgrav  ** utmpx utility functions
72383d2307dSDag-Erling Smørgrav  **
72483d2307dSDag-Erling Smørgrav  ** These functions manipulate struct utmpx, accounting for system
72583d2307dSDag-Erling Smørgrav  ** variations.
72683d2307dSDag-Erling Smørgrav  **/
72783d2307dSDag-Erling Smørgrav 
72883d2307dSDag-Erling Smørgrav #if defined(USE_UTMPX) || defined (USE_WTMPX)
72983d2307dSDag-Erling Smørgrav /* build the utmpx structure */
73083d2307dSDag-Erling Smørgrav void
set_utmpx_time(struct logininfo * li,struct utmpx * utx)73183d2307dSDag-Erling Smørgrav set_utmpx_time(struct logininfo *li, struct utmpx *utx)
73283d2307dSDag-Erling Smørgrav {
733aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMPX)
73483d2307dSDag-Erling Smørgrav 	utx->ut_tv.tv_sec = li->tv_sec;
73583d2307dSDag-Erling Smørgrav 	utx->ut_tv.tv_usec = li->tv_usec;
736aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMPX)
73783d2307dSDag-Erling Smørgrav 	utx->ut_time = li->tv_sec;
738aa49c926SDag-Erling Smørgrav # endif
73983d2307dSDag-Erling Smørgrav }
74083d2307dSDag-Erling Smørgrav 
74183d2307dSDag-Erling Smørgrav void
construct_utmpx(struct logininfo * li,struct utmpx * utx)74283d2307dSDag-Erling Smørgrav construct_utmpx(struct logininfo *li, struct utmpx *utx)
74383d2307dSDag-Erling Smørgrav {
744e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
745e73e9afaSDag-Erling Smørgrav 	struct sockaddr_in6 *sa6;
746e73e9afaSDag-Erling Smørgrav #  endif
74783d2307dSDag-Erling Smørgrav 	memset(utx, '\0', sizeof(*utx));
748aa49c926SDag-Erling Smørgrav 
74983d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX
75083d2307dSDag-Erling Smørgrav 	line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
75183d2307dSDag-Erling Smørgrav # endif
75283d2307dSDag-Erling Smørgrav 
75383d2307dSDag-Erling Smørgrav 	/* this is done here to keep utmp constants out of loginrec.h */
75483d2307dSDag-Erling Smørgrav 	switch (li->type) {
75583d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
75683d2307dSDag-Erling Smørgrav 		utx->ut_type = USER_PROCESS;
75783d2307dSDag-Erling Smørgrav 		break;
75883d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
75983d2307dSDag-Erling Smørgrav 		utx->ut_type = DEAD_PROCESS;
76083d2307dSDag-Erling Smørgrav 		break;
76183d2307dSDag-Erling Smørgrav 	}
76283d2307dSDag-Erling Smørgrav 	line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
76383d2307dSDag-Erling Smørgrav 	set_utmpx_time(li, utx);
76483d2307dSDag-Erling Smørgrav 	utx->ut_pid = li->pid;
765aa49c926SDag-Erling Smørgrav 
76683d2307dSDag-Erling Smørgrav 	/* strncpy(): Don't necessarily want null termination */
767b40cdde6SEd Schouten 	strncpy(utx->ut_user, li->username,
768b40cdde6SEd Schouten 	    MIN_SIZEOF(utx->ut_user, li->username));
76983d2307dSDag-Erling Smørgrav 
77083d2307dSDag-Erling Smørgrav 	if (li->type == LTYPE_LOGOUT)
77183d2307dSDag-Erling Smørgrav 		return;
77283d2307dSDag-Erling Smørgrav 
77383d2307dSDag-Erling Smørgrav 	/*
77483d2307dSDag-Erling Smørgrav 	 * These fields are only used when logging in, and are blank
77583d2307dSDag-Erling Smørgrav 	 * for logouts.
77683d2307dSDag-Erling Smørgrav 	 */
77783d2307dSDag-Erling Smørgrav 
77883d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX
779aa49c926SDag-Erling Smørgrav 	strncpy(utx->ut_host, li->hostname,
780aa49c926SDag-Erling Smørgrav 	    MIN_SIZEOF(utx->ut_host, li->hostname));
78183d2307dSDag-Erling Smørgrav # endif
78219261079SEd Maste # ifdef HAVE_SS_IN_UTMPX
78319261079SEd Maste 	utx->ut_ss = li->hostaddr.sa_storage;
78419261079SEd Maste # endif
78583d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMPX
78683d2307dSDag-Erling Smørgrav 	/* this is just a 32-bit IP address */
78783d2307dSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET)
78883d2307dSDag-Erling Smørgrav 		utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
78983d2307dSDag-Erling Smørgrav # endif
790e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP
791e73e9afaSDag-Erling Smørgrav 	/* this is just a 128-bit IPv6 address */
792e73e9afaSDag-Erling Smørgrav 	if (li->hostaddr.sa.sa_family == AF_INET6) {
793e73e9afaSDag-Erling Smørgrav 		sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
794bc5531deSDag-Erling Smørgrav 		memcpy(utx->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
795e73e9afaSDag-Erling Smørgrav 		if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
796bc5531deSDag-Erling Smørgrav 			utx->ut_addr_v6[0] = utx->ut_addr_v6[3];
797bc5531deSDag-Erling Smørgrav 			utx->ut_addr_v6[1] = 0;
798bc5531deSDag-Erling Smørgrav 			utx->ut_addr_v6[2] = 0;
799bc5531deSDag-Erling Smørgrav 			utx->ut_addr_v6[3] = 0;
800e73e9afaSDag-Erling Smørgrav 		}
801e73e9afaSDag-Erling Smørgrav 	}
802e73e9afaSDag-Erling Smørgrav # endif
80383d2307dSDag-Erling Smørgrav # ifdef HAVE_SYSLEN_IN_UTMPX
80483d2307dSDag-Erling Smørgrav 	/* ut_syslen is the length of the utx_host string */
805*1323ec57SEd Maste 	utx->ut_syslen = MINIMUM(strlen(li->hostname), sizeof(utx->ut_host));
80683d2307dSDag-Erling Smørgrav # endif
80783d2307dSDag-Erling Smørgrav }
80883d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX || USE_WTMPX */
80983d2307dSDag-Erling Smørgrav 
81083d2307dSDag-Erling Smørgrav /**
81183d2307dSDag-Erling Smørgrav  ** Low-level utmp functions
81283d2307dSDag-Erling Smørgrav  **/
81383d2307dSDag-Erling Smørgrav 
81483d2307dSDag-Erling Smørgrav /* FIXME: (ATL) utmp_write_direct needs testing */
81583d2307dSDag-Erling Smørgrav #ifdef USE_UTMP
81683d2307dSDag-Erling Smørgrav 
81783d2307dSDag-Erling Smørgrav /* if we can, use pututline() etc. */
81883d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
81983d2307dSDag-Erling Smørgrav 	defined(HAVE_PUTUTLINE)
82083d2307dSDag-Erling Smørgrav #  define UTMP_USE_LIBRARY
82183d2307dSDag-Erling Smørgrav # endif
82283d2307dSDag-Erling Smørgrav 
82383d2307dSDag-Erling Smørgrav 
82483d2307dSDag-Erling Smørgrav /* write a utmp entry with the system's help (pututline() and pals) */
82583d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
82683d2307dSDag-Erling Smørgrav static int
utmp_write_library(struct logininfo * li,struct utmp * ut)82783d2307dSDag-Erling Smørgrav utmp_write_library(struct logininfo *li, struct utmp *ut)
82883d2307dSDag-Erling Smørgrav {
82983d2307dSDag-Erling Smørgrav 	setutent();
83083d2307dSDag-Erling Smørgrav 	pututline(ut);
83183d2307dSDag-Erling Smørgrav #  ifdef HAVE_ENDUTENT
83283d2307dSDag-Erling Smørgrav 	endutent();
83383d2307dSDag-Erling Smørgrav #  endif
834aa49c926SDag-Erling Smørgrav 	return (1);
83583d2307dSDag-Erling Smørgrav }
83683d2307dSDag-Erling Smørgrav # else /* UTMP_USE_LIBRARY */
83783d2307dSDag-Erling Smørgrav 
838aa49c926SDag-Erling Smørgrav /*
839aa49c926SDag-Erling Smørgrav  * Write a utmp entry direct to the file
840aa49c926SDag-Erling Smørgrav  * This is a slightly modification of code in OpenBSD's login.c
841aa49c926SDag-Erling Smørgrav  */
84283d2307dSDag-Erling Smørgrav static int
utmp_write_direct(struct logininfo * li,struct utmp * ut)84383d2307dSDag-Erling Smørgrav utmp_write_direct(struct logininfo *li, struct utmp *ut)
84483d2307dSDag-Erling Smørgrav {
84583d2307dSDag-Erling Smørgrav 	struct utmp old_ut;
84683d2307dSDag-Erling Smørgrav 	register int fd;
84783d2307dSDag-Erling Smørgrav 	int tty;
84883d2307dSDag-Erling Smørgrav 
84983d2307dSDag-Erling Smørgrav 	/* FIXME: (ATL) ttyslot() needs local implementation */
85083d2307dSDag-Erling Smørgrav 
85183d2307dSDag-Erling Smørgrav #if defined(HAVE_GETTTYENT)
852aa49c926SDag-Erling Smørgrav 	struct ttyent *ty;
85383d2307dSDag-Erling Smørgrav 
85483d2307dSDag-Erling Smørgrav 	tty=0;
85583d2307dSDag-Erling Smørgrav 	setttyent();
856aa49c926SDag-Erling Smørgrav 	while (NULL != (ty = getttyent())) {
85783d2307dSDag-Erling Smørgrav 		tty++;
85883d2307dSDag-Erling Smørgrav 		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
85983d2307dSDag-Erling Smørgrav 			break;
86083d2307dSDag-Erling Smørgrav 	}
86183d2307dSDag-Erling Smørgrav 	endttyent();
86283d2307dSDag-Erling Smørgrav 
863aa49c926SDag-Erling Smørgrav 	if (NULL == ty) {
86421e764dfSDag-Erling Smørgrav 		logit("%s: tty not found", __func__);
86521e764dfSDag-Erling Smørgrav 		return (0);
86683d2307dSDag-Erling Smørgrav 	}
86783d2307dSDag-Erling Smørgrav #else /* FIXME */
86883d2307dSDag-Erling Smørgrav 
86983d2307dSDag-Erling Smørgrav 	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
87083d2307dSDag-Erling Smørgrav 
87183d2307dSDag-Erling Smørgrav #endif /* HAVE_GETTTYENT */
87283d2307dSDag-Erling Smørgrav 
87383d2307dSDag-Erling Smørgrav 	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
87421e764dfSDag-Erling Smørgrav 		off_t pos, ret;
87521e764dfSDag-Erling Smørgrav 
87621e764dfSDag-Erling Smørgrav 		pos = (off_t)tty * sizeof(struct utmp);
87721e764dfSDag-Erling Smørgrav 		if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
878aa49c926SDag-Erling Smørgrav 			logit("%s: lseek: %s", __func__, strerror(errno));
8794a421b63SDag-Erling Smørgrav 			close(fd);
88021e764dfSDag-Erling Smørgrav 			return (0);
88121e764dfSDag-Erling Smørgrav 		}
88221e764dfSDag-Erling Smørgrav 		if (ret != pos) {
883aa49c926SDag-Erling Smørgrav 			logit("%s: Couldn't seek to tty %d slot in %s",
884aa49c926SDag-Erling Smørgrav 			    __func__, tty, UTMP_FILE);
8854a421b63SDag-Erling Smørgrav 			close(fd);
88621e764dfSDag-Erling Smørgrav 			return (0);
88721e764dfSDag-Erling Smørgrav 		}
88883d2307dSDag-Erling Smørgrav 		/*
88983d2307dSDag-Erling Smørgrav 		 * Prevent luser from zero'ing out ut_host.
89083d2307dSDag-Erling Smørgrav 		 * If the new ut_line is empty but the old one is not
89183d2307dSDag-Erling Smørgrav 		 * and ut_line and ut_name match, preserve the old ut_line.
89283d2307dSDag-Erling Smørgrav 		 */
89383d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
89483d2307dSDag-Erling Smørgrav 		    (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
89583d2307dSDag-Erling Smørgrav 		    (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
896aa49c926SDag-Erling Smørgrav 		    (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0))
897aa49c926SDag-Erling Smørgrav 			memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
89883d2307dSDag-Erling Smørgrav 
89921e764dfSDag-Erling Smørgrav 		if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
900aa49c926SDag-Erling Smørgrav 			logit("%s: lseek: %s", __func__, strerror(errno));
9014a421b63SDag-Erling Smørgrav 			close(fd);
90221e764dfSDag-Erling Smørgrav 			return (0);
90321e764dfSDag-Erling Smørgrav 		}
90421e764dfSDag-Erling Smørgrav 		if (ret != pos) {
905aa49c926SDag-Erling Smørgrav 			logit("%s: Couldn't seek to tty %d slot in %s",
90621e764dfSDag-Erling Smørgrav 			    __func__, tty, UTMP_FILE);
9074a421b63SDag-Erling Smørgrav 			close(fd);
90821e764dfSDag-Erling Smørgrav 			return (0);
90921e764dfSDag-Erling Smørgrav 		}
910aa49c926SDag-Erling Smørgrav 		if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
91121e764dfSDag-Erling Smørgrav 			logit("%s: error writing %s: %s", __func__,
91283d2307dSDag-Erling Smørgrav 			    UTMP_FILE, strerror(errno));
9134a421b63SDag-Erling Smørgrav 			close(fd);
9144a421b63SDag-Erling Smørgrav 			return (0);
915aa49c926SDag-Erling Smørgrav 		}
91683d2307dSDag-Erling Smørgrav 
917aa49c926SDag-Erling Smørgrav 		close(fd);
918aa49c926SDag-Erling Smørgrav 		return (1);
91983d2307dSDag-Erling Smørgrav 	} else {
920aa49c926SDag-Erling Smørgrav 		return (0);
92183d2307dSDag-Erling Smørgrav 	}
92283d2307dSDag-Erling Smørgrav }
92383d2307dSDag-Erling Smørgrav # endif /* UTMP_USE_LIBRARY */
92483d2307dSDag-Erling Smørgrav 
92583d2307dSDag-Erling Smørgrav static int
utmp_perform_login(struct logininfo * li)92683d2307dSDag-Erling Smørgrav utmp_perform_login(struct logininfo *li)
92783d2307dSDag-Erling Smørgrav {
92883d2307dSDag-Erling Smørgrav 	struct utmp ut;
92983d2307dSDag-Erling Smørgrav 
93083d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
93183d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
93283d2307dSDag-Erling Smørgrav 	if (!utmp_write_library(li, &ut)) {
933aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_library() failed", __func__);
934aa49c926SDag-Erling Smørgrav 		return (0);
93583d2307dSDag-Erling Smørgrav 	}
93683d2307dSDag-Erling Smørgrav # else
93783d2307dSDag-Erling Smørgrav 	if (!utmp_write_direct(li, &ut)) {
938aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_direct() failed", __func__);
939aa49c926SDag-Erling Smørgrav 		return (0);
94083d2307dSDag-Erling Smørgrav 	}
94183d2307dSDag-Erling Smørgrav # endif
942aa49c926SDag-Erling Smørgrav 	return (1);
94383d2307dSDag-Erling Smørgrav }
94483d2307dSDag-Erling Smørgrav 
94583d2307dSDag-Erling Smørgrav 
94683d2307dSDag-Erling Smørgrav static int
utmp_perform_logout(struct logininfo * li)94783d2307dSDag-Erling Smørgrav utmp_perform_logout(struct logininfo *li)
94883d2307dSDag-Erling Smørgrav {
94983d2307dSDag-Erling Smørgrav 	struct utmp ut;
95083d2307dSDag-Erling Smørgrav 
95183d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
95283d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY
95383d2307dSDag-Erling Smørgrav 	if (!utmp_write_library(li, &ut)) {
954aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_library() failed", __func__);
955aa49c926SDag-Erling Smørgrav 		return (0);
95683d2307dSDag-Erling Smørgrav 	}
95783d2307dSDag-Erling Smørgrav # else
95883d2307dSDag-Erling Smørgrav 	if (!utmp_write_direct(li, &ut)) {
959aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_direct() failed", __func__);
960aa49c926SDag-Erling Smørgrav 		return (0);
96183d2307dSDag-Erling Smørgrav 	}
96283d2307dSDag-Erling Smørgrav # endif
963aa49c926SDag-Erling Smørgrav 	return (1);
96483d2307dSDag-Erling Smørgrav }
96583d2307dSDag-Erling Smørgrav 
96683d2307dSDag-Erling Smørgrav 
96783d2307dSDag-Erling Smørgrav int
utmp_write_entry(struct logininfo * li)96883d2307dSDag-Erling Smørgrav utmp_write_entry(struct logininfo *li)
96983d2307dSDag-Erling Smørgrav {
97083d2307dSDag-Erling Smørgrav 	switch(li->type) {
97183d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
972aa49c926SDag-Erling Smørgrav 		return (utmp_perform_login(li));
97383d2307dSDag-Erling Smørgrav 
97483d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
975aa49c926SDag-Erling Smørgrav 		return (utmp_perform_logout(li));
97683d2307dSDag-Erling Smørgrav 
97783d2307dSDag-Erling Smørgrav 	default:
978aa49c926SDag-Erling Smørgrav 		logit("%s: invalid type field", __func__);
979aa49c926SDag-Erling Smørgrav 		return (0);
98083d2307dSDag-Erling Smørgrav 	}
98183d2307dSDag-Erling Smørgrav }
98283d2307dSDag-Erling Smørgrav #endif /* USE_UTMP */
98383d2307dSDag-Erling Smørgrav 
98483d2307dSDag-Erling Smørgrav 
98583d2307dSDag-Erling Smørgrav /**
98683d2307dSDag-Erling Smørgrav  ** Low-level utmpx functions
98783d2307dSDag-Erling Smørgrav  **/
98883d2307dSDag-Erling Smørgrav 
98983d2307dSDag-Erling Smørgrav /* not much point if we don't want utmpx entries */
99083d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX
99183d2307dSDag-Erling Smørgrav 
99283d2307dSDag-Erling Smørgrav /* if we have the wherewithall, use pututxline etc. */
99383d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
99483d2307dSDag-Erling Smørgrav 	defined(HAVE_PUTUTXLINE)
99583d2307dSDag-Erling Smørgrav #  define UTMPX_USE_LIBRARY
99683d2307dSDag-Erling Smørgrav # endif
99783d2307dSDag-Erling Smørgrav 
99883d2307dSDag-Erling Smørgrav 
99983d2307dSDag-Erling Smørgrav /* write a utmpx entry with the system's help (pututxline() and pals) */
100083d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
100183d2307dSDag-Erling Smørgrav static int
utmpx_write_library(struct logininfo * li,struct utmpx * utx)100283d2307dSDag-Erling Smørgrav utmpx_write_library(struct logininfo *li, struct utmpx *utx)
100383d2307dSDag-Erling Smørgrav {
100483d2307dSDag-Erling Smørgrav 	setutxent();
100583d2307dSDag-Erling Smørgrav 	pututxline(utx);
100683d2307dSDag-Erling Smørgrav 
100783d2307dSDag-Erling Smørgrav #  ifdef HAVE_ENDUTXENT
100883d2307dSDag-Erling Smørgrav 	endutxent();
100983d2307dSDag-Erling Smørgrav #  endif
1010aa49c926SDag-Erling Smørgrav 	return (1);
101183d2307dSDag-Erling Smørgrav }
101283d2307dSDag-Erling Smørgrav 
101383d2307dSDag-Erling Smørgrav # else /* UTMPX_USE_LIBRARY */
101483d2307dSDag-Erling Smørgrav 
101583d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */
101683d2307dSDag-Erling Smørgrav static int
utmpx_write_direct(struct logininfo * li,struct utmpx * utx)101783d2307dSDag-Erling Smørgrav utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
101883d2307dSDag-Erling Smørgrav {
1019aa49c926SDag-Erling Smørgrav 	logit("%s: not implemented!", __func__);
1020aa49c926SDag-Erling Smørgrav 	return (0);
102183d2307dSDag-Erling Smørgrav }
102283d2307dSDag-Erling Smørgrav # endif /* UTMPX_USE_LIBRARY */
102383d2307dSDag-Erling Smørgrav 
102483d2307dSDag-Erling Smørgrav static int
utmpx_perform_login(struct logininfo * li)102583d2307dSDag-Erling Smørgrav utmpx_perform_login(struct logininfo *li)
102683d2307dSDag-Erling Smørgrav {
102783d2307dSDag-Erling Smørgrav 	struct utmpx utx;
102883d2307dSDag-Erling Smørgrav 
102983d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
103083d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
103183d2307dSDag-Erling Smørgrav 	if (!utmpx_write_library(li, &utx)) {
1032aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_library() failed", __func__);
1033aa49c926SDag-Erling Smørgrav 		return (0);
103483d2307dSDag-Erling Smørgrav 	}
103583d2307dSDag-Erling Smørgrav # else
103683d2307dSDag-Erling Smørgrav 	if (!utmpx_write_direct(li, &ut)) {
1037aa49c926SDag-Erling Smørgrav 		logit("%s: utmp_write_direct() failed", __func__);
1038aa49c926SDag-Erling Smørgrav 		return (0);
103983d2307dSDag-Erling Smørgrav 	}
104083d2307dSDag-Erling Smørgrav # endif
1041aa49c926SDag-Erling Smørgrav 	return (1);
104283d2307dSDag-Erling Smørgrav }
104383d2307dSDag-Erling Smørgrav 
104483d2307dSDag-Erling Smørgrav 
104583d2307dSDag-Erling Smørgrav static int
utmpx_perform_logout(struct logininfo * li)104683d2307dSDag-Erling Smørgrav utmpx_perform_logout(struct logininfo *li)
104783d2307dSDag-Erling Smørgrav {
104883d2307dSDag-Erling Smørgrav 	struct utmpx utx;
104983d2307dSDag-Erling Smørgrav 
105083d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
105183d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX
105283d2307dSDag-Erling Smørgrav 	line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
105383d2307dSDag-Erling Smørgrav # endif
105483d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX
105583d2307dSDag-Erling Smørgrav 	utx.ut_type = DEAD_PROCESS;
105683d2307dSDag-Erling Smørgrav # endif
105783d2307dSDag-Erling Smørgrav 
105883d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY
105983d2307dSDag-Erling Smørgrav 	utmpx_write_library(li, &utx);
106083d2307dSDag-Erling Smørgrav # else
106183d2307dSDag-Erling Smørgrav 	utmpx_write_direct(li, &utx);
106283d2307dSDag-Erling Smørgrav # endif
1063aa49c926SDag-Erling Smørgrav 	return (1);
106483d2307dSDag-Erling Smørgrav }
106583d2307dSDag-Erling Smørgrav 
106683d2307dSDag-Erling Smørgrav int
utmpx_write_entry(struct logininfo * li)106783d2307dSDag-Erling Smørgrav utmpx_write_entry(struct logininfo *li)
106883d2307dSDag-Erling Smørgrav {
106983d2307dSDag-Erling Smørgrav 	switch(li->type) {
107083d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
1071aa49c926SDag-Erling Smørgrav 		return (utmpx_perform_login(li));
107283d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
1073aa49c926SDag-Erling Smørgrav 		return (utmpx_perform_logout(li));
107483d2307dSDag-Erling Smørgrav 	default:
1075aa49c926SDag-Erling Smørgrav 		logit("%s: invalid type field", __func__);
1076aa49c926SDag-Erling Smørgrav 		return (0);
107783d2307dSDag-Erling Smørgrav 	}
107883d2307dSDag-Erling Smørgrav }
107983d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX */
108083d2307dSDag-Erling Smørgrav 
108183d2307dSDag-Erling Smørgrav 
108283d2307dSDag-Erling Smørgrav /**
108383d2307dSDag-Erling Smørgrav  ** Low-level wtmp functions
108483d2307dSDag-Erling Smørgrav  **/
108583d2307dSDag-Erling Smørgrav 
108683d2307dSDag-Erling Smørgrav #ifdef USE_WTMP
108783d2307dSDag-Erling Smørgrav 
1088aa49c926SDag-Erling Smørgrav /*
1089aa49c926SDag-Erling Smørgrav  * Write a wtmp entry direct to the end of the file
1090aa49c926SDag-Erling Smørgrav  * This is a slight modification of code in OpenBSD's logwtmp.c
1091aa49c926SDag-Erling Smørgrav  */
109283d2307dSDag-Erling Smørgrav static int
wtmp_write(struct logininfo * li,struct utmp * ut)109383d2307dSDag-Erling Smørgrav wtmp_write(struct logininfo *li, struct utmp *ut)
109483d2307dSDag-Erling Smørgrav {
109583d2307dSDag-Erling Smørgrav 	struct stat buf;
109683d2307dSDag-Erling Smørgrav 	int fd, ret = 1;
109783d2307dSDag-Erling Smørgrav 
109883d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1099aa49c926SDag-Erling Smørgrav 		logit("%s: problem writing %s: %s", __func__,
110083d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
1101aa49c926SDag-Erling Smørgrav 		return (0);
110283d2307dSDag-Erling Smørgrav 	}
110383d2307dSDag-Erling Smørgrav 	if (fstat(fd, &buf) == 0)
1104cf2b5f3bSDag-Erling Smørgrav 		if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
110583d2307dSDag-Erling Smørgrav 			ftruncate(fd, buf.st_size);
1106aa49c926SDag-Erling Smørgrav 			logit("%s: problem writing %s: %s", __func__,
110783d2307dSDag-Erling Smørgrav 			    WTMP_FILE, strerror(errno));
110883d2307dSDag-Erling Smørgrav 			ret = 0;
110983d2307dSDag-Erling Smørgrav 		}
1110aa49c926SDag-Erling Smørgrav 	close(fd);
1111aa49c926SDag-Erling Smørgrav 	return (ret);
111283d2307dSDag-Erling Smørgrav }
111383d2307dSDag-Erling Smørgrav 
111483d2307dSDag-Erling Smørgrav static int
wtmp_perform_login(struct logininfo * li)111583d2307dSDag-Erling Smørgrav wtmp_perform_login(struct logininfo *li)
111683d2307dSDag-Erling Smørgrav {
111783d2307dSDag-Erling Smørgrav 	struct utmp ut;
111883d2307dSDag-Erling Smørgrav 
111983d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
1120aa49c926SDag-Erling Smørgrav 	return (wtmp_write(li, &ut));
112183d2307dSDag-Erling Smørgrav }
112283d2307dSDag-Erling Smørgrav 
112383d2307dSDag-Erling Smørgrav 
112483d2307dSDag-Erling Smørgrav static int
wtmp_perform_logout(struct logininfo * li)112583d2307dSDag-Erling Smørgrav wtmp_perform_logout(struct logininfo *li)
112683d2307dSDag-Erling Smørgrav {
112783d2307dSDag-Erling Smørgrav 	struct utmp ut;
112883d2307dSDag-Erling Smørgrav 
112983d2307dSDag-Erling Smørgrav 	construct_utmp(li, &ut);
1130aa49c926SDag-Erling Smørgrav 	return (wtmp_write(li, &ut));
113183d2307dSDag-Erling Smørgrav }
113283d2307dSDag-Erling Smørgrav 
113383d2307dSDag-Erling Smørgrav 
113483d2307dSDag-Erling Smørgrav int
wtmp_write_entry(struct logininfo * li)113583d2307dSDag-Erling Smørgrav wtmp_write_entry(struct logininfo *li)
113683d2307dSDag-Erling Smørgrav {
113783d2307dSDag-Erling Smørgrav 	switch(li->type) {
113883d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
1139aa49c926SDag-Erling Smørgrav 		return (wtmp_perform_login(li));
114083d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
1141aa49c926SDag-Erling Smørgrav 		return (wtmp_perform_logout(li));
114283d2307dSDag-Erling Smørgrav 	default:
1143aa49c926SDag-Erling Smørgrav 		logit("%s: invalid type field", __func__);
1144aa49c926SDag-Erling Smørgrav 		return (0);
114583d2307dSDag-Erling Smørgrav 	}
114683d2307dSDag-Erling Smørgrav }
114783d2307dSDag-Erling Smørgrav 
114883d2307dSDag-Erling Smørgrav 
1149aa49c926SDag-Erling Smørgrav /*
1150aa49c926SDag-Erling Smørgrav  * Notes on fetching login data from wtmp/wtmpx
115183d2307dSDag-Erling Smørgrav  *
115283d2307dSDag-Erling Smørgrav  * Logouts are usually recorded with (amongst other things) a blank
115383d2307dSDag-Erling Smørgrav  * username on a given tty line.  However, some systems (HP-UX is one)
115483d2307dSDag-Erling Smørgrav  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
115583d2307dSDag-Erling Smørgrav  *
115683d2307dSDag-Erling Smørgrav  * Since we're only looking for logins here, we know that the username
115783d2307dSDag-Erling Smørgrav  * must be set correctly. On systems that leave it in, we check for
115883d2307dSDag-Erling Smørgrav  * ut_type==USER_PROCESS (indicating a login.)
115983d2307dSDag-Erling Smørgrav  *
116083d2307dSDag-Erling Smørgrav  * Portability: Some systems may set something other than USER_PROCESS
116183d2307dSDag-Erling Smørgrav  * to indicate a login process. I don't know of any as I write. Also,
116283d2307dSDag-Erling Smørgrav  * it's possible that some systems may both leave the username in
116383d2307dSDag-Erling Smørgrav  * place and not have ut_type.
116483d2307dSDag-Erling Smørgrav  */
116583d2307dSDag-Erling Smørgrav 
116683d2307dSDag-Erling Smørgrav /* return true if this wtmp entry indicates a login */
116783d2307dSDag-Erling Smørgrav static int
wtmp_islogin(struct logininfo * li,struct utmp * ut)116883d2307dSDag-Erling Smørgrav wtmp_islogin(struct logininfo *li, struct utmp *ut)
116983d2307dSDag-Erling Smørgrav {
117083d2307dSDag-Erling Smørgrav 	if (strncmp(li->username, ut->ut_name,
117183d2307dSDag-Erling Smørgrav 	    MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
117283d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP
117383d2307dSDag-Erling Smørgrav 		if (ut->ut_type & USER_PROCESS)
1174aa49c926SDag-Erling Smørgrav 			return (1);
117583d2307dSDag-Erling Smørgrav # else
1176aa49c926SDag-Erling Smørgrav 		return (1);
117783d2307dSDag-Erling Smørgrav # endif
117883d2307dSDag-Erling Smørgrav 	}
1179aa49c926SDag-Erling Smørgrav 	return (0);
118083d2307dSDag-Erling Smørgrav }
118183d2307dSDag-Erling Smørgrav 
118283d2307dSDag-Erling Smørgrav int
wtmp_get_entry(struct logininfo * li)118383d2307dSDag-Erling Smørgrav wtmp_get_entry(struct logininfo *li)
118483d2307dSDag-Erling Smørgrav {
118583d2307dSDag-Erling Smørgrav 	struct stat st;
118683d2307dSDag-Erling Smørgrav 	struct utmp ut;
118783d2307dSDag-Erling Smørgrav 	int fd, found = 0;
118883d2307dSDag-Erling Smørgrav 
118983d2307dSDag-Erling Smørgrav 	/* Clear the time entries in our logininfo */
119083d2307dSDag-Erling Smørgrav 	li->tv_sec = li->tv_usec = 0;
119183d2307dSDag-Erling Smørgrav 
119283d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1193aa49c926SDag-Erling Smørgrav 		logit("%s: problem opening %s: %s", __func__,
119483d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
1195aa49c926SDag-Erling Smørgrav 		return (0);
119683d2307dSDag-Erling Smørgrav 	}
119783d2307dSDag-Erling Smørgrav 	if (fstat(fd, &st) != 0) {
1198aa49c926SDag-Erling Smørgrav 		logit("%s: couldn't stat %s: %s", __func__,
119983d2307dSDag-Erling Smørgrav 		    WTMP_FILE, strerror(errno));
120083d2307dSDag-Erling Smørgrav 		close(fd);
1201aa49c926SDag-Erling Smørgrav 		return (0);
120283d2307dSDag-Erling Smørgrav 	}
120383d2307dSDag-Erling Smørgrav 
120483d2307dSDag-Erling Smørgrav 	/* Seek to the start of the last struct utmp */
120583d2307dSDag-Erling Smørgrav 	if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
120683d2307dSDag-Erling Smørgrav 		/* Looks like we've got a fresh wtmp file */
120783d2307dSDag-Erling Smørgrav 		close(fd);
1208aa49c926SDag-Erling Smørgrav 		return (0);
120983d2307dSDag-Erling Smørgrav 	}
121083d2307dSDag-Erling Smørgrav 
121183d2307dSDag-Erling Smørgrav 	while (!found) {
121283d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
1213aa49c926SDag-Erling Smørgrav 			logit("%s: read of %s failed: %s", __func__,
121483d2307dSDag-Erling Smørgrav 			    WTMP_FILE, strerror(errno));
121583d2307dSDag-Erling Smørgrav 			close (fd);
1216aa49c926SDag-Erling Smørgrav 			return (0);
121783d2307dSDag-Erling Smørgrav 		}
121883d2307dSDag-Erling Smørgrav 		if (wtmp_islogin(li, &ut) ) {
121983d2307dSDag-Erling Smørgrav 			found = 1;
1220aa49c926SDag-Erling Smørgrav 			/*
1221aa49c926SDag-Erling Smørgrav 			 * We've already checked for a time in struct
1222aa49c926SDag-Erling Smørgrav 			 * utmp, in login_getlast()
1223aa49c926SDag-Erling Smørgrav 			 */
122483d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMP
122583d2307dSDag-Erling Smørgrav 			li->tv_sec = ut.ut_time;
122683d2307dSDag-Erling Smørgrav # else
122783d2307dSDag-Erling Smørgrav #  if HAVE_TV_IN_UTMP
122883d2307dSDag-Erling Smørgrav 			li->tv_sec = ut.ut_tv.tv_sec;
122983d2307dSDag-Erling Smørgrav #  endif
123083d2307dSDag-Erling Smørgrav # endif
123183d2307dSDag-Erling Smørgrav 			line_fullname(li->line, ut.ut_line,
123283d2307dSDag-Erling Smørgrav 			    MIN_SIZEOF(li->line, ut.ut_line));
123383d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP
123483d2307dSDag-Erling Smørgrav 			strlcpy(li->hostname, ut.ut_host,
123583d2307dSDag-Erling Smørgrav 			    MIN_SIZEOF(li->hostname, ut.ut_host));
123683d2307dSDag-Erling Smørgrav # endif
123783d2307dSDag-Erling Smørgrav 			continue;
123883d2307dSDag-Erling Smørgrav 		}
123983d2307dSDag-Erling Smørgrav 		/* Seek back 2 x struct utmp */
124083d2307dSDag-Erling Smørgrav 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
124183d2307dSDag-Erling Smørgrav 			/* We've found the start of the file, so quit */
124283d2307dSDag-Erling Smørgrav 			close(fd);
1243aa49c926SDag-Erling Smørgrav 			return (0);
124483d2307dSDag-Erling Smørgrav 		}
124583d2307dSDag-Erling Smørgrav 	}
124683d2307dSDag-Erling Smørgrav 
124783d2307dSDag-Erling Smørgrav 	/* We found an entry. Tidy up and return */
124883d2307dSDag-Erling Smørgrav 	close(fd);
1249aa49c926SDag-Erling Smørgrav 	return (1);
125083d2307dSDag-Erling Smørgrav }
125183d2307dSDag-Erling Smørgrav # endif /* USE_WTMP */
125283d2307dSDag-Erling Smørgrav 
125383d2307dSDag-Erling Smørgrav 
125483d2307dSDag-Erling Smørgrav /**
125583d2307dSDag-Erling Smørgrav  ** Low-level wtmpx functions
125683d2307dSDag-Erling Smørgrav  **/
125783d2307dSDag-Erling Smørgrav 
125883d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX
1259aa49c926SDag-Erling Smørgrav /*
1260aa49c926SDag-Erling Smørgrav  * Write a wtmpx entry direct to the end of the file
1261aa49c926SDag-Erling Smørgrav  * This is a slight modification of code in OpenBSD's logwtmp.c
1262aa49c926SDag-Erling Smørgrav  */
126383d2307dSDag-Erling Smørgrav static int
wtmpx_write(struct logininfo * li,struct utmpx * utx)126483d2307dSDag-Erling Smørgrav wtmpx_write(struct logininfo *li, struct utmpx *utx)
126583d2307dSDag-Erling Smørgrav {
12661ec0d754SDag-Erling Smørgrav #ifndef HAVE_UPDWTMPX
126783d2307dSDag-Erling Smørgrav 	struct stat buf;
126883d2307dSDag-Erling Smørgrav 	int fd, ret = 1;
126983d2307dSDag-Erling Smørgrav 
127083d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1271aa49c926SDag-Erling Smørgrav 		logit("%s: problem opening %s: %s", __func__,
127283d2307dSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
1273aa49c926SDag-Erling Smørgrav 		return (0);
127483d2307dSDag-Erling Smørgrav 	}
127583d2307dSDag-Erling Smørgrav 
127683d2307dSDag-Erling Smørgrav 	if (fstat(fd, &buf) == 0)
1277cf2b5f3bSDag-Erling Smørgrav 		if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
127883d2307dSDag-Erling Smørgrav 			ftruncate(fd, buf.st_size);
1279aa49c926SDag-Erling Smørgrav 			logit("%s: problem writing %s: %s", __func__,
128083d2307dSDag-Erling Smørgrav 			    WTMPX_FILE, strerror(errno));
128183d2307dSDag-Erling Smørgrav 			ret = 0;
128283d2307dSDag-Erling Smørgrav 		}
1283aa49c926SDag-Erling Smørgrav 	close(fd);
128483d2307dSDag-Erling Smørgrav 
1285aa49c926SDag-Erling Smørgrav 	return (ret);
12861ec0d754SDag-Erling Smørgrav #else
12871ec0d754SDag-Erling Smørgrav 	updwtmpx(WTMPX_FILE, utx);
1288aa49c926SDag-Erling Smørgrav 	return (1);
12891ec0d754SDag-Erling Smørgrav #endif
129083d2307dSDag-Erling Smørgrav }
129183d2307dSDag-Erling Smørgrav 
129283d2307dSDag-Erling Smørgrav 
129383d2307dSDag-Erling Smørgrav static int
wtmpx_perform_login(struct logininfo * li)129483d2307dSDag-Erling Smørgrav wtmpx_perform_login(struct logininfo *li)
129583d2307dSDag-Erling Smørgrav {
129683d2307dSDag-Erling Smørgrav 	struct utmpx utx;
129783d2307dSDag-Erling Smørgrav 
129883d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
1299aa49c926SDag-Erling Smørgrav 	return (wtmpx_write(li, &utx));
130083d2307dSDag-Erling Smørgrav }
130183d2307dSDag-Erling Smørgrav 
130283d2307dSDag-Erling Smørgrav 
130383d2307dSDag-Erling Smørgrav static int
wtmpx_perform_logout(struct logininfo * li)130483d2307dSDag-Erling Smørgrav wtmpx_perform_logout(struct logininfo *li)
130583d2307dSDag-Erling Smørgrav {
130683d2307dSDag-Erling Smørgrav 	struct utmpx utx;
130783d2307dSDag-Erling Smørgrav 
130883d2307dSDag-Erling Smørgrav 	construct_utmpx(li, &utx);
1309aa49c926SDag-Erling Smørgrav 	return (wtmpx_write(li, &utx));
131083d2307dSDag-Erling Smørgrav }
131183d2307dSDag-Erling Smørgrav 
131283d2307dSDag-Erling Smørgrav 
131383d2307dSDag-Erling Smørgrav int
wtmpx_write_entry(struct logininfo * li)131483d2307dSDag-Erling Smørgrav wtmpx_write_entry(struct logininfo *li)
131583d2307dSDag-Erling Smørgrav {
131683d2307dSDag-Erling Smørgrav 	switch(li->type) {
131783d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
1318aa49c926SDag-Erling Smørgrav 		return (wtmpx_perform_login(li));
131983d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
1320aa49c926SDag-Erling Smørgrav 		return (wtmpx_perform_logout(li));
132183d2307dSDag-Erling Smørgrav 	default:
1322aa49c926SDag-Erling Smørgrav 		logit("%s: invalid type field", __func__);
1323aa49c926SDag-Erling Smørgrav 		return (0);
132483d2307dSDag-Erling Smørgrav 	}
132583d2307dSDag-Erling Smørgrav }
132683d2307dSDag-Erling Smørgrav 
132783d2307dSDag-Erling Smørgrav /* Please see the notes above wtmp_islogin() for information about the
132883d2307dSDag-Erling Smørgrav    next two functions */
132983d2307dSDag-Erling Smørgrav 
133083d2307dSDag-Erling Smørgrav /* Return true if this wtmpx entry indicates a login */
133183d2307dSDag-Erling Smørgrav static int
wtmpx_islogin(struct logininfo * li,struct utmpx * utx)133283d2307dSDag-Erling Smørgrav wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
133383d2307dSDag-Erling Smørgrav {
1334b15c8340SDag-Erling Smørgrav 	if (strncmp(li->username, utx->ut_user,
1335b15c8340SDag-Erling Smørgrav 	    MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {
133683d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX
133783d2307dSDag-Erling Smørgrav 		if (utx->ut_type == USER_PROCESS)
1338aa49c926SDag-Erling Smørgrav 			return (1);
133983d2307dSDag-Erling Smørgrav # else
1340aa49c926SDag-Erling Smørgrav 		return (1);
134183d2307dSDag-Erling Smørgrav # endif
134283d2307dSDag-Erling Smørgrav 	}
1343aa49c926SDag-Erling Smørgrav 	return (0);
134483d2307dSDag-Erling Smørgrav }
134583d2307dSDag-Erling Smørgrav 
134683d2307dSDag-Erling Smørgrav 
134783d2307dSDag-Erling Smørgrav int
wtmpx_get_entry(struct logininfo * li)134883d2307dSDag-Erling Smørgrav wtmpx_get_entry(struct logininfo *li)
134983d2307dSDag-Erling Smørgrav {
135083d2307dSDag-Erling Smørgrav 	struct stat st;
135183d2307dSDag-Erling Smørgrav 	struct utmpx utx;
135283d2307dSDag-Erling Smørgrav 	int fd, found=0;
135383d2307dSDag-Erling Smørgrav 
135483d2307dSDag-Erling Smørgrav 	/* Clear the time entries */
135583d2307dSDag-Erling Smørgrav 	li->tv_sec = li->tv_usec = 0;
135683d2307dSDag-Erling Smørgrav 
135783d2307dSDag-Erling Smørgrav 	if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1358aa49c926SDag-Erling Smørgrav 		logit("%s: problem opening %s: %s", __func__,
135983d2307dSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
1360aa49c926SDag-Erling Smørgrav 		return (0);
136183d2307dSDag-Erling Smørgrav 	}
136283d2307dSDag-Erling Smørgrav 	if (fstat(fd, &st) != 0) {
1363aa49c926SDag-Erling Smørgrav 		logit("%s: couldn't stat %s: %s", __func__,
1364f388f5efSDag-Erling Smørgrav 		    WTMPX_FILE, strerror(errno));
136583d2307dSDag-Erling Smørgrav 		close(fd);
1366aa49c926SDag-Erling Smørgrav 		return (0);
136783d2307dSDag-Erling Smørgrav 	}
136883d2307dSDag-Erling Smørgrav 
136983d2307dSDag-Erling Smørgrav 	/* Seek to the start of the last struct utmpx */
137083d2307dSDag-Erling Smørgrav 	if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
137183d2307dSDag-Erling Smørgrav 		/* probably a newly rotated wtmpx file */
137283d2307dSDag-Erling Smørgrav 		close(fd);
1373aa49c926SDag-Erling Smørgrav 		return (0);
137483d2307dSDag-Erling Smørgrav 	}
137583d2307dSDag-Erling Smørgrav 
137683d2307dSDag-Erling Smørgrav 	while (!found) {
137783d2307dSDag-Erling Smørgrav 		if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
1378aa49c926SDag-Erling Smørgrav 			logit("%s: read of %s failed: %s", __func__,
137983d2307dSDag-Erling Smørgrav 			    WTMPX_FILE, strerror(errno));
138083d2307dSDag-Erling Smørgrav 			close (fd);
1381aa49c926SDag-Erling Smørgrav 			return (0);
138283d2307dSDag-Erling Smørgrav 		}
1383aa49c926SDag-Erling Smørgrav 		/*
1384aa49c926SDag-Erling Smørgrav 		 * Logouts are recorded as a blank username on a particular
1385aa49c926SDag-Erling Smørgrav 		 * line. So, we just need to find the username in struct utmpx
1386aa49c926SDag-Erling Smørgrav 		 */
138783d2307dSDag-Erling Smørgrav 		if (wtmpx_islogin(li, &utx)) {
1388f388f5efSDag-Erling Smørgrav 			found = 1;
1389aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMPX)
139083d2307dSDag-Erling Smørgrav 			li->tv_sec = utx.ut_tv.tv_sec;
1391aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMPX)
139283d2307dSDag-Erling Smørgrav 			li->tv_sec = utx.ut_time;
139383d2307dSDag-Erling Smørgrav # endif
139483d2307dSDag-Erling Smørgrav 			line_fullname(li->line, utx.ut_line, sizeof(li->line));
1395aa49c926SDag-Erling Smørgrav # if defined(HAVE_HOST_IN_UTMPX)
139683d2307dSDag-Erling Smørgrav 			strlcpy(li->hostname, utx.ut_host,
139783d2307dSDag-Erling Smørgrav 			    MIN_SIZEOF(li->hostname, utx.ut_host));
139883d2307dSDag-Erling Smørgrav # endif
139983d2307dSDag-Erling Smørgrav 			continue;
140083d2307dSDag-Erling Smørgrav 		}
140183d2307dSDag-Erling Smørgrav 		if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
140283d2307dSDag-Erling Smørgrav 			close(fd);
1403aa49c926SDag-Erling Smørgrav 			return (0);
140483d2307dSDag-Erling Smørgrav 		}
140583d2307dSDag-Erling Smørgrav 	}
140683d2307dSDag-Erling Smørgrav 
140783d2307dSDag-Erling Smørgrav 	close(fd);
1408aa49c926SDag-Erling Smørgrav 	return (1);
140983d2307dSDag-Erling Smørgrav }
141083d2307dSDag-Erling Smørgrav #endif /* USE_WTMPX */
141183d2307dSDag-Erling Smørgrav 
141283d2307dSDag-Erling Smørgrav /**
141383d2307dSDag-Erling Smørgrav  ** Low-level libutil login() functions
141483d2307dSDag-Erling Smørgrav  **/
141583d2307dSDag-Erling Smørgrav 
141683d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN
141783d2307dSDag-Erling Smørgrav static int
syslogin_perform_login(struct logininfo * li)141883d2307dSDag-Erling Smørgrav syslogin_perform_login(struct logininfo *li)
141983d2307dSDag-Erling Smørgrav {
142083d2307dSDag-Erling Smørgrav 	struct utmp *ut;
142183d2307dSDag-Erling Smørgrav 
1422aa49c926SDag-Erling Smørgrav 	ut = xmalloc(sizeof(*ut));
142383d2307dSDag-Erling Smørgrav 	construct_utmp(li, ut);
142483d2307dSDag-Erling Smørgrav 	login(ut);
1425e73e9afaSDag-Erling Smørgrav 	free(ut);
142683d2307dSDag-Erling Smørgrav 
1427aa49c926SDag-Erling Smørgrav 	return (1);
142883d2307dSDag-Erling Smørgrav }
142983d2307dSDag-Erling Smørgrav 
143083d2307dSDag-Erling Smørgrav static int
syslogin_perform_logout(struct logininfo * li)143183d2307dSDag-Erling Smørgrav syslogin_perform_logout(struct logininfo *li)
143283d2307dSDag-Erling Smørgrav {
143383d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGOUT
14345962c0e9SDag-Erling Smørgrav 	char line[UT_LINESIZE];
143583d2307dSDag-Erling Smørgrav 
143683d2307dSDag-Erling Smørgrav 	(void)line_stripname(line, li->line, sizeof(line));
143783d2307dSDag-Erling Smørgrav 
1438aa49c926SDag-Erling Smørgrav 	if (!logout(line))
1439aa49c926SDag-Erling Smørgrav 		logit("%s: logout() returned an error", __func__);
144083d2307dSDag-Erling Smørgrav #  ifdef HAVE_LOGWTMP
1441aa49c926SDag-Erling Smørgrav 	else
144283d2307dSDag-Erling Smørgrav 		logwtmp(line, "", "");
144383d2307dSDag-Erling Smørgrav #  endif
144483d2307dSDag-Erling Smørgrav 	/* FIXME: (ATL - if the need arises) What to do if we have
144583d2307dSDag-Erling Smørgrav 	 * login, but no logout?  what if logout but no logwtmp? All
144683d2307dSDag-Erling Smørgrav 	 * routines are in libutil so they should all be there,
144783d2307dSDag-Erling Smørgrav 	 * but... */
144883d2307dSDag-Erling Smørgrav # endif
1449aa49c926SDag-Erling Smørgrav 	return (1);
145083d2307dSDag-Erling Smørgrav }
145183d2307dSDag-Erling Smørgrav 
145283d2307dSDag-Erling Smørgrav int
syslogin_write_entry(struct logininfo * li)145383d2307dSDag-Erling Smørgrav syslogin_write_entry(struct logininfo *li)
145483d2307dSDag-Erling Smørgrav {
145583d2307dSDag-Erling Smørgrav 	switch (li->type) {
145683d2307dSDag-Erling Smørgrav 	case LTYPE_LOGIN:
1457aa49c926SDag-Erling Smørgrav 		return (syslogin_perform_login(li));
145883d2307dSDag-Erling Smørgrav 	case LTYPE_LOGOUT:
1459aa49c926SDag-Erling Smørgrav 		return (syslogin_perform_logout(li));
146083d2307dSDag-Erling Smørgrav 	default:
1461aa49c926SDag-Erling Smørgrav 		logit("%s: Invalid type field", __func__);
1462aa49c926SDag-Erling Smørgrav 		return (0);
146383d2307dSDag-Erling Smørgrav 	}
146483d2307dSDag-Erling Smørgrav }
146583d2307dSDag-Erling Smørgrav #endif /* USE_LOGIN */
146683d2307dSDag-Erling Smørgrav 
146783d2307dSDag-Erling Smørgrav /* end of file log-syslogin.c */
146883d2307dSDag-Erling Smørgrav 
146983d2307dSDag-Erling Smørgrav /**
147083d2307dSDag-Erling Smørgrav  ** Low-level lastlog functions
147183d2307dSDag-Erling Smørgrav  **/
147283d2307dSDag-Erling Smørgrav 
147383d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG
147483d2307dSDag-Erling Smørgrav 
1475cce7d346SDag-Erling Smørgrav #if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME)
1476cce7d346SDag-Erling Smørgrav /* open the file (using filemode) and seek to the login entry */
147783d2307dSDag-Erling Smørgrav static int
lastlog_openseek(struct logininfo * li,int * fd,int filemode)1478cce7d346SDag-Erling Smørgrav lastlog_openseek(struct logininfo *li, int *fd, int filemode)
147983d2307dSDag-Erling Smørgrav {
1480cce7d346SDag-Erling Smørgrav 	off_t offset;
1481cce7d346SDag-Erling Smørgrav 	char lastlog_file[1024];
148283d2307dSDag-Erling Smørgrav 	struct stat st;
148383d2307dSDag-Erling Smørgrav 
148483d2307dSDag-Erling Smørgrav 	if (stat(LASTLOG_FILE, &st) != 0) {
1485aa49c926SDag-Erling Smørgrav 		logit("%s: Couldn't stat %s: %s", __func__,
1486aa49c926SDag-Erling Smørgrav 		    LASTLOG_FILE, strerror(errno));
1487aa49c926SDag-Erling Smørgrav 		return (0);
148883d2307dSDag-Erling Smørgrav 	}
1489cce7d346SDag-Erling Smørgrav 	if (S_ISDIR(st.st_mode)) {
149083d2307dSDag-Erling Smørgrav 		snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
149183d2307dSDag-Erling Smørgrav 		    LASTLOG_FILE, li->username);
1492cce7d346SDag-Erling Smørgrav 	} else if (S_ISREG(st.st_mode)) {
1493cce7d346SDag-Erling Smørgrav 		strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1494cce7d346SDag-Erling Smørgrav 	} else {
1495aa49c926SDag-Erling Smørgrav 		logit("%s: %.100s is not a file or directory!", __func__,
149683d2307dSDag-Erling Smørgrav 		    LASTLOG_FILE);
1497aa49c926SDag-Erling Smørgrav 		return (0);
149883d2307dSDag-Erling Smørgrav 	}
149983d2307dSDag-Erling Smørgrav 
1500cf2b5f3bSDag-Erling Smørgrav 	*fd = open(lastlog_file, filemode, 0600);
150183d2307dSDag-Erling Smørgrav 	if (*fd < 0) {
1502aa49c926SDag-Erling Smørgrav 		debug("%s: Couldn't open %s: %s", __func__,
150383d2307dSDag-Erling Smørgrav 		    lastlog_file, strerror(errno));
1504aa49c926SDag-Erling Smørgrav 		return (0);
150583d2307dSDag-Erling Smørgrav 	}
150683d2307dSDag-Erling Smørgrav 
1507cce7d346SDag-Erling Smørgrav 	if (S_ISREG(st.st_mode)) {
150883d2307dSDag-Erling Smørgrav 		/* find this uid's offset in the lastlog file */
15094a421b63SDag-Erling Smørgrav 		offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));
151083d2307dSDag-Erling Smørgrav 
151183d2307dSDag-Erling Smørgrav 		if (lseek(*fd, offset, SEEK_SET) != offset) {
1512aa49c926SDag-Erling Smørgrav 			logit("%s: %s->lseek(): %s", __func__,
151383d2307dSDag-Erling Smørgrav 			    lastlog_file, strerror(errno));
15144a421b63SDag-Erling Smørgrav 			close(*fd);
1515aa49c926SDag-Erling Smørgrav 			return (0);
151683d2307dSDag-Erling Smørgrav 		}
151783d2307dSDag-Erling Smørgrav 	}
151883d2307dSDag-Erling Smørgrav 
1519aa49c926SDag-Erling Smørgrav 	return (1);
152083d2307dSDag-Erling Smørgrav }
1521cce7d346SDag-Erling Smørgrav #endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */
152283d2307dSDag-Erling Smørgrav 
1523cce7d346SDag-Erling Smørgrav #ifdef LASTLOG_WRITE_PUTUTXLINE
1524cce7d346SDag-Erling Smørgrav int
lastlog_write_entry(struct logininfo * li)1525cce7d346SDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li)
1526cce7d346SDag-Erling Smørgrav {
1527cce7d346SDag-Erling Smørgrav 	switch(li->type) {
1528cce7d346SDag-Erling Smørgrav 	case LTYPE_LOGIN:
1529cce7d346SDag-Erling Smørgrav 		return 1; /* lastlog written by pututxline */
1530cce7d346SDag-Erling Smørgrav 	default:
1531cce7d346SDag-Erling Smørgrav 		logit("lastlog_write_entry: Invalid type field");
1532cce7d346SDag-Erling Smørgrav 		return 0;
1533cce7d346SDag-Erling Smørgrav 	}
1534cce7d346SDag-Erling Smørgrav }
1535cce7d346SDag-Erling Smørgrav #else /* LASTLOG_WRITE_PUTUTXLINE */
1536cce7d346SDag-Erling Smørgrav int
lastlog_write_entry(struct logininfo * li)1537cce7d346SDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li)
153883d2307dSDag-Erling Smørgrav {
153983d2307dSDag-Erling Smørgrav 	struct lastlog last;
154083d2307dSDag-Erling Smørgrav 	int fd;
154183d2307dSDag-Erling Smørgrav 
1542cce7d346SDag-Erling Smørgrav 	switch(li->type) {
1543cce7d346SDag-Erling Smørgrav 	case LTYPE_LOGIN:
154483d2307dSDag-Erling Smørgrav 		/* create our struct lastlog */
1545cce7d346SDag-Erling Smørgrav 		memset(&last, '\0', sizeof(last));
1546cce7d346SDag-Erling Smørgrav 		line_stripname(last.ll_line, li->line, sizeof(last.ll_line));
1547cce7d346SDag-Erling Smørgrav 		strlcpy(last.ll_host, li->hostname,
1548cce7d346SDag-Erling Smørgrav 		    MIN_SIZEOF(last.ll_host, li->hostname));
1549cce7d346SDag-Erling Smørgrav 		last.ll_time = li->tv_sec;
155083d2307dSDag-Erling Smørgrav 
155183d2307dSDag-Erling Smørgrav 		if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
155283d2307dSDag-Erling Smørgrav 			return (0);
155383d2307dSDag-Erling Smørgrav 
155483d2307dSDag-Erling Smørgrav 		/* write the entry */
1555cf2b5f3bSDag-Erling Smørgrav 		if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
155683d2307dSDag-Erling Smørgrav 			close(fd);
1557aa49c926SDag-Erling Smørgrav 			logit("%s: Error writing to %s: %s", __func__,
155883d2307dSDag-Erling Smørgrav 			    LASTLOG_FILE, strerror(errno));
1559aa49c926SDag-Erling Smørgrav 			return (0);
156083d2307dSDag-Erling Smørgrav 		}
156183d2307dSDag-Erling Smørgrav 
156283d2307dSDag-Erling Smørgrav 		close(fd);
1563aa49c926SDag-Erling Smørgrav 		return (1);
156483d2307dSDag-Erling Smørgrav 	default:
1565aa49c926SDag-Erling Smørgrav 		logit("%s: Invalid type field", __func__);
1566aa49c926SDag-Erling Smørgrav 		return (0);
156783d2307dSDag-Erling Smørgrav 	}
156883d2307dSDag-Erling Smørgrav }
1569cce7d346SDag-Erling Smørgrav #endif /* LASTLOG_WRITE_PUTUTXLINE */
157083d2307dSDag-Erling Smørgrav 
1571cce7d346SDag-Erling Smørgrav #ifdef HAVE_GETLASTLOGXBYNAME
1572cce7d346SDag-Erling Smørgrav int
lastlog_get_entry(struct logininfo * li)1573cce7d346SDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li)
157483d2307dSDag-Erling Smørgrav {
1575cce7d346SDag-Erling Smørgrav 	struct lastlogx l, *ll;
157683d2307dSDag-Erling Smørgrav 
1577cce7d346SDag-Erling Smørgrav 	if ((ll = getlastlogxbyname(li->username, &l)) == NULL) {
1578cce7d346SDag-Erling Smørgrav 		memset(&l, '\0', sizeof(l));
1579cce7d346SDag-Erling Smørgrav 		ll = &l;
1580cce7d346SDag-Erling Smørgrav 	}
1581cce7d346SDag-Erling Smørgrav 	line_fullname(li->line, ll->ll_line, sizeof(li->line));
1582cce7d346SDag-Erling Smørgrav 	strlcpy(li->hostname, ll->ll_host,
1583cce7d346SDag-Erling Smørgrav 		MIN_SIZEOF(li->hostname, ll->ll_host));
1584cce7d346SDag-Erling Smørgrav 	li->tv_sec = ll->ll_tv.tv_sec;
1585cce7d346SDag-Erling Smørgrav 	li->tv_usec = ll->ll_tv.tv_usec;
1586cce7d346SDag-Erling Smørgrav 	return (1);
1587cce7d346SDag-Erling Smørgrav }
1588cce7d346SDag-Erling Smørgrav #else /* HAVE_GETLASTLOGXBYNAME */
158983d2307dSDag-Erling Smørgrav int
lastlog_get_entry(struct logininfo * li)159083d2307dSDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li)
159183d2307dSDag-Erling Smørgrav {
159283d2307dSDag-Erling Smørgrav 	struct lastlog last;
1593e73e9afaSDag-Erling Smørgrav 	int fd, ret;
159483d2307dSDag-Erling Smørgrav 
159583d2307dSDag-Erling Smørgrav 	if (!lastlog_openseek(li, &fd, O_RDONLY))
1596e73e9afaSDag-Erling Smørgrav 		return (0);
159783d2307dSDag-Erling Smørgrav 
1598e73e9afaSDag-Erling Smørgrav 	ret = atomicio(read, fd, &last, sizeof(last));
159983d2307dSDag-Erling Smørgrav 	close(fd);
1600e73e9afaSDag-Erling Smørgrav 
1601e73e9afaSDag-Erling Smørgrav 	switch (ret) {
1602e73e9afaSDag-Erling Smørgrav 	case 0:
1603e73e9afaSDag-Erling Smørgrav 		memset(&last, '\0', sizeof(last));
1604e73e9afaSDag-Erling Smørgrav 		/* FALLTHRU */
1605e73e9afaSDag-Erling Smørgrav 	case sizeof(last):
1606cce7d346SDag-Erling Smørgrav 		line_fullname(li->line, last.ll_line, sizeof(li->line));
1607cce7d346SDag-Erling Smørgrav 		strlcpy(li->hostname, last.ll_host,
1608cce7d346SDag-Erling Smørgrav 		    MIN_SIZEOF(li->hostname, last.ll_host));
1609cce7d346SDag-Erling Smørgrav 		li->tv_sec = last.ll_time;
1610e73e9afaSDag-Erling Smørgrav 		return (1);
1611e73e9afaSDag-Erling Smørgrav 	case -1:
1612e73e9afaSDag-Erling Smørgrav 		error("%s: Error reading from %s: %s", __func__,
161383d2307dSDag-Erling Smørgrav 		    LASTLOG_FILE, strerror(errno));
1614e73e9afaSDag-Erling Smørgrav 		return (0);
1615e73e9afaSDag-Erling Smørgrav 	default:
1616e73e9afaSDag-Erling Smørgrav 		error("%s: Error reading from %s: Expecting %d, got %d",
1617b74df5b2SDag-Erling Smørgrav 		    __func__, LASTLOG_FILE, (int)sizeof(last), ret);
1618e73e9afaSDag-Erling Smørgrav 		return (0);
161983d2307dSDag-Erling Smørgrav 	}
162083d2307dSDag-Erling Smørgrav 
1621e73e9afaSDag-Erling Smørgrav 	/* NOTREACHED */
1622e73e9afaSDag-Erling Smørgrav 	return (0);
162383d2307dSDag-Erling Smørgrav }
1624cce7d346SDag-Erling Smørgrav #endif /* HAVE_GETLASTLOGXBYNAME */
162583d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */
1626aa49c926SDag-Erling Smørgrav 
16278ad9b54aSDag-Erling Smørgrav #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
16288ad9b54aSDag-Erling Smørgrav     defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
1629b40cdde6SEd Schouten int
utmpx_get_entry(struct logininfo * li)1630b40cdde6SEd Schouten utmpx_get_entry(struct logininfo *li)
1631b40cdde6SEd Schouten {
1632b40cdde6SEd Schouten 	struct utmpx *utx;
1633b40cdde6SEd Schouten 
1634b40cdde6SEd Schouten 	if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
1635b40cdde6SEd Schouten 		return (0);
1636b40cdde6SEd Schouten 	utx = getutxuser(li->username);
1637b40cdde6SEd Schouten 	if (utx == NULL) {
1638b40cdde6SEd Schouten 		endutxent();
1639b40cdde6SEd Schouten 		return (0);
1640b40cdde6SEd Schouten 	}
1641b40cdde6SEd Schouten 
1642b40cdde6SEd Schouten 	line_fullname(li->line, utx->ut_line,
1643b40cdde6SEd Schouten 	    MIN_SIZEOF(li->line, utx->ut_line));
1644b40cdde6SEd Schouten 	strlcpy(li->hostname, utx->ut_host,
1645b40cdde6SEd Schouten 	    MIN_SIZEOF(li->hostname, utx->ut_host));
1646b40cdde6SEd Schouten 	li->tv_sec = utx->ut_tv.tv_sec;
1647b40cdde6SEd Schouten 	li->tv_usec = utx->ut_tv.tv_usec;
1648b40cdde6SEd Schouten 	endutxent();
1649b40cdde6SEd Schouten 	return (1);
1650b40cdde6SEd Schouten }
16518ad9b54aSDag-Erling Smørgrav #endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */
1652b40cdde6SEd Schouten 
1653aa49c926SDag-Erling Smørgrav #ifdef USE_BTMP
1654aa49c926SDag-Erling Smørgrav   /*
1655aa49c926SDag-Erling Smørgrav    * Logs failed login attempts in _PATH_BTMP if that exists.
1656aa49c926SDag-Erling Smørgrav    * The most common login failure is to give password instead of username.
1657aa49c926SDag-Erling Smørgrav    * So the _PATH_BTMP file checked for the correct permission, so that
1658aa49c926SDag-Erling Smørgrav    * only root can read it.
1659aa49c926SDag-Erling Smørgrav    */
1660aa49c926SDag-Erling Smørgrav 
1661aa49c926SDag-Erling Smørgrav void
record_failed_login(struct ssh * ssh,const char * username,const char * hostname,const char * ttyn)166219261079SEd Maste record_failed_login(struct ssh *ssh, const char *username, const char *hostname,
1663aa49c926SDag-Erling Smørgrav     const char *ttyn)
1664aa49c926SDag-Erling Smørgrav {
1665aa49c926SDag-Erling Smørgrav 	int fd;
1666aa49c926SDag-Erling Smørgrav 	struct utmp ut;
1667aa49c926SDag-Erling Smørgrav 	struct sockaddr_storage from;
1668b74df5b2SDag-Erling Smørgrav 	socklen_t fromlen = sizeof(from);
1669aa49c926SDag-Erling Smørgrav 	struct sockaddr_in *a4;
1670aa49c926SDag-Erling Smørgrav 	struct sockaddr_in6 *a6;
1671aa49c926SDag-Erling Smørgrav 	time_t t;
1672aa49c926SDag-Erling Smørgrav 	struct stat fst;
1673aa49c926SDag-Erling Smørgrav 
1674aa49c926SDag-Erling Smørgrav 	if (geteuid() != 0)
1675aa49c926SDag-Erling Smørgrav 		return;
1676aa49c926SDag-Erling Smørgrav 	if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) {
1677aa49c926SDag-Erling Smørgrav 		debug("Unable to open the btmp file %s: %s", _PATH_BTMP,
1678aa49c926SDag-Erling Smørgrav 		    strerror(errno));
1679aa49c926SDag-Erling Smørgrav 		return;
1680aa49c926SDag-Erling Smørgrav 	}
1681aa49c926SDag-Erling Smørgrav 	if (fstat(fd, &fst) < 0) {
1682aa49c926SDag-Erling Smørgrav 		logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP,
1683aa49c926SDag-Erling Smørgrav 		    strerror(errno));
1684aa49c926SDag-Erling Smørgrav 		goto out;
1685aa49c926SDag-Erling Smørgrav 	}
16864a421b63SDag-Erling Smørgrav 	if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){
1687aa49c926SDag-Erling Smørgrav 		logit("Excess permission or bad ownership on file %s",
1688aa49c926SDag-Erling Smørgrav 		    _PATH_BTMP);
1689aa49c926SDag-Erling Smørgrav 		goto out;
1690aa49c926SDag-Erling Smørgrav 	}
1691aa49c926SDag-Erling Smørgrav 
1692aa49c926SDag-Erling Smørgrav 	memset(&ut, 0, sizeof(ut));
1693aa49c926SDag-Erling Smørgrav 	/* strncpy because we don't necessarily want nul termination */
1694aa49c926SDag-Erling Smørgrav 	strncpy(ut.ut_user, username, sizeof(ut.ut_user));
1695aa49c926SDag-Erling Smørgrav 	strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line));
1696aa49c926SDag-Erling Smørgrav 
1697aa49c926SDag-Erling Smørgrav 	time(&t);
1698aa49c926SDag-Erling Smørgrav 	ut.ut_time = t;     /* ut_time is not always a time_t */
1699aa49c926SDag-Erling Smørgrav 	ut.ut_type = LOGIN_PROCESS;
1700aa49c926SDag-Erling Smørgrav 	ut.ut_pid = getpid();
1701aa49c926SDag-Erling Smørgrav 
1702aa49c926SDag-Erling Smørgrav 	/* strncpy because we don't necessarily want nul termination */
1703aa49c926SDag-Erling Smørgrav 	strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
1704aa49c926SDag-Erling Smørgrav 
170519261079SEd Maste 	if (ssh_packet_connection_is_on_socket(ssh) &&
170619261079SEd Maste 	    getpeername(ssh_packet_get_connection_in(ssh),
1707aa49c926SDag-Erling Smørgrav 	    (struct sockaddr *)&from, &fromlen) == 0) {
1708aa49c926SDag-Erling Smørgrav 		ipv64_normalise_mapped(&from, &fromlen);
1709aa49c926SDag-Erling Smørgrav 		if (from.ss_family == AF_INET) {
1710aa49c926SDag-Erling Smørgrav 			a4 = (struct sockaddr_in *)&from;
1711aa49c926SDag-Erling Smørgrav 			memcpy(&ut.ut_addr, &(a4->sin_addr),
1712aa49c926SDag-Erling Smørgrav 			    MIN_SIZEOF(ut.ut_addr, a4->sin_addr));
1713aa49c926SDag-Erling Smørgrav 		}
1714aa49c926SDag-Erling Smørgrav #ifdef HAVE_ADDR_V6_IN_UTMP
1715aa49c926SDag-Erling Smørgrav 		if (from.ss_family == AF_INET6) {
1716aa49c926SDag-Erling Smørgrav 			a6 = (struct sockaddr_in6 *)&from;
1717aa49c926SDag-Erling Smørgrav 			memcpy(&ut.ut_addr_v6, &(a6->sin6_addr),
1718aa49c926SDag-Erling Smørgrav 			    MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr));
1719aa49c926SDag-Erling Smørgrav 		}
1720aa49c926SDag-Erling Smørgrav #endif
1721aa49c926SDag-Erling Smørgrav 	}
1722aa49c926SDag-Erling Smørgrav 
1723aa49c926SDag-Erling Smørgrav 	if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut))
1724aa49c926SDag-Erling Smørgrav 		error("Failed to write to %s: %s", _PATH_BTMP,
1725aa49c926SDag-Erling Smørgrav 		    strerror(errno));
1726aa49c926SDag-Erling Smørgrav 
1727aa49c926SDag-Erling Smørgrav out:
1728aa49c926SDag-Erling Smørgrav 	close(fd);
1729aa49c926SDag-Erling Smørgrav }
1730aa49c926SDag-Erling Smørgrav #endif	/* USE_BTMP */
1731