blob: 4219b9aef3de6c93e761afdca1fe976e2f8322be [file] [log] [blame]
andre2ff7b5d2000-06-03 14:57:40 +00001/*
2 * Copyright (c) 2000 Andre Lucas. All rights reserved.
andre61e67252000-06-04 17:07:49 +00003 * Portions copyright (c) 1998 Todd C. Miller
4 * Portions copyright (c) 1996 Jason Downs
5 * Portions copyright (c) 1996 Theo de Raadt
andre2ff7b5d2000-06-03 14:57:40 +00006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
andre2ff7b5d2000-06-03 14:57:40 +000015 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
Darren Tucker2fba9932005-02-02 23:30:24 +110028/*
29 * The btmp logging code is derived from login.c from util-linux and is under
30 * the the following license:
31 *
32 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms are permitted
36 * provided that the above copyright notice and this paragraph are
37 * duplicated in all such forms and that any documentation,
38 * advertising materials, and other materials related to such
39 * distribution and use acknowledge that the software was developed
40 * by the University of California, Berkeley. The name of the
41 * University may not be used to endorse or promote products derived
42 * from this software without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46 */
47
48
Kevin Stevesef4eea92001-02-05 12:42:17 +000049/**
andre2ff7b5d2000-06-03 14:57:40 +000050 ** loginrec.c: platform-independent login recording and lastlog retrieval
51 **/
52
andre61e67252000-06-04 17:07:49 +000053/*
Damien Miller8899ed32004-09-12 15:18:55 +100054 * The new login code explained
55 * ============================
56 *
57 * This code attempts to provide a common interface to login recording
58 * (utmp and friends) and last login time retrieval.
59 *
60 * Its primary means of achieving this is to use 'struct logininfo', a
61 * union of all the useful fields in the various different types of
62 * system login record structures one finds on UNIX variants.
63 *
64 * We depend on autoconf to define which recording methods are to be
65 * used, and which fields are contained in the relevant data structures
66 * on the local system. Many C preprocessor symbols affect which code
67 * gets compiled here.
68 *
69 * The code is designed to make it easy to modify a particular
70 * recording method, without affecting other methods nor requiring so
71 * many nested conditional compilation blocks as were commonplace in
72 * the old code.
73 *
74 * For login recording, we try to use the local system's libraries as
75 * these are clearly most likely to work correctly. For utmp systems
76 * this usually means login() and logout() or setutent() etc., probably
77 * in libutil, along with logwtmp() etc. On these systems, we fall back
78 * to writing the files directly if we have to, though this method
79 * requires very thorough testing so we do not corrupt local auditing
80 * information. These files and their access methods are very system
81 * specific indeed.
82 *
83 * For utmpx systems, the corresponding library functions are
84 * setutxent() etc. To the author's knowledge, all utmpx systems have
85 * these library functions and so no direct write is attempted. If such
86 * a system exists and needs support, direct analogues of the [uw]tmp
87 * code should suffice.
88 *
89 * Retrieving the time of last login ('lastlog') is in some ways even
90 * more problemmatic than login recording. Some systems provide a
91 * simple table of all users which we seek based on uid and retrieve a
92 * relatively standard structure. Others record the same information in
93 * a directory with a separate file, and others don't record the
94 * information separately at all. For systems in the latter category,
95 * we look backwards in the wtmp or wtmpx file for the last login entry
96 * for our user. Naturally this is slower and on busy systems could
97 * incur a significant performance penalty.
98 *
99 * Calling the new code
100 * --------------------
101 *
102 * In OpenSSH all login recording and retrieval is performed in
103 * login.c. Here you'll find working examples. Also, in the logintest.c
104 * program there are more examples.
105 *
106 * Internal handler calling method
107 * -------------------------------
108 *
109 * When a call is made to login_login() or login_logout(), both
110 * routines set a struct logininfo flag defining which action (log in,
111 * or log out) is to be taken. They both then call login_write(), which
112 * calls whichever of the many structure-specific handlers autoconf
113 * selects for the local system.
114 *
115 * The handlers themselves handle system data structure specifics. Both
116 * struct utmp and struct utmpx have utility functions (see
117 * construct_utmp*()) to try to make it simpler to add extra systems
118 * that introduce new features to either structure.
119 *
120 * While it may seem terribly wasteful to replicate so much similar
121 * code for each method, experience has shown that maintaining code to
122 * write both struct utmp and utmpx in one function, whilst maintaining
123 * support for all systems whether they have library support or not, is
124 * a difficult and time-consuming task.
125 *
126 * Lastlog support proceeds similarly. Functions login_get_lastlog()
127 * (and its OpenSSH-tuned friend login_get_lastlog_time()) call
128 * getlast_entry(), which tries one of three methods to find the last
129 * login time. It uses local system lastlog support if it can,
130 * otherwise it tries wtmp or wtmpx before giving up and returning 0,
131 * meaning "tilt".
132 *
133 * Maintenance
134 * -----------
135 *
136 * In many cases it's possible to tweak autoconf to select the correct
137 * methods for a particular platform, either by improving the detection
138 * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
139 * symbols for the platform.
140 *
141 * Use logintest to check which symbols are defined before modifying
142 * configure.ac and loginrec.c. (You have to build logintest yourself
143 * with 'make logintest' as it's not built by default.)
144 *
145 * Otherwise, patches to the specific method(s) are very helpful!
146 */
andre2ff7b5d2000-06-03 14:57:40 +0000147
148#include "includes.h"
149
Damien Miller62772522006-03-15 14:01:11 +1100150#include <sys/types.h>
151#include <sys/stat.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +1000152#include <sys/socket.h>
153
154#include <netinet/in.h>
Damien Miller62772522006-03-15 14:01:11 +1100155
Darren Tucker2c1a02a2006-07-12 22:40:50 +1000156#include <errno.h>
Damien Millera1738e42006-07-10 21:33:04 +1000157#include <fcntl.h>
Darren Tuckerf19bbc32006-09-07 22:57:53 +1000158#ifdef HAVE_PATHS_H
159# include <paths.h>
160#endif
Damien Miller9f2abc42006-07-10 20:53:08 +1000161#include <pwd.h>
Damien Millerded319c2006-09-01 15:38:36 +1000162#include <stdarg.h>
Damien Millerb8fe89c2006-07-24 14:51:00 +1000163#include <string.h>
Darren Tuckerd757e692007-04-29 12:10:57 +1000164#include <time.h>
Damien Millerb8fe89c2006-07-24 14:51:00 +1000165#include <unistd.h>
Damien Miller9f2abc42006-07-10 20:53:08 +1000166
andre2ff7b5d2000-06-03 14:57:40 +0000167#include "xmalloc.h"
Damien Millerd7834352006-08-05 12:39:39 +1000168#include "key.h"
169#include "hostfile.h"
170#include "ssh.h"
andre2ff7b5d2000-06-03 14:57:40 +0000171#include "loginrec.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000172#include "log.h"
173#include "atomicio.h"
Darren Tucker2fba9932005-02-02 23:30:24 +1100174#include "packet.h"
175#include "canohost.h"
Darren Tucker269a1ea2005-02-03 00:20:53 +1100176#include "auth.h"
Darren Tuckera39f83e2005-02-15 22:19:28 +1100177#include "buffer.h"
andre2ff7b5d2000-06-03 14:57:40 +0000178
Ben Lindstromdcca9812000-11-10 03:28:31 +0000179#ifdef HAVE_UTIL_H
Damien Miller8899ed32004-09-12 15:18:55 +1000180# include <util.h>
Ben Lindstromdcca9812000-11-10 03:28:31 +0000181#endif
andre2ff7b5d2000-06-03 14:57:40 +0000182
183/**
184 ** prototypes for helper functions in this file
185 **/
186
187#if HAVE_UTMP_H
andre2ff7b5d2000-06-03 14:57:40 +0000188void set_utmp_time(struct logininfo *li, struct utmp *ut);
189void construct_utmp(struct logininfo *li, struct utmp *ut);
190#endif
191
192#ifdef HAVE_UTMPX_H
andre2ff7b5d2000-06-03 14:57:40 +0000193void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
194void construct_utmpx(struct logininfo *li, struct utmpx *ut);
195#endif
196
197int utmp_write_entry(struct logininfo *li);
198int utmpx_write_entry(struct logininfo *li);
199int wtmp_write_entry(struct logininfo *li);
200int wtmpx_write_entry(struct logininfo *li);
201int lastlog_write_entry(struct logininfo *li);
202int syslogin_write_entry(struct logininfo *li);
203
204int getlast_entry(struct logininfo *li);
205int lastlog_get_entry(struct logininfo *li);
Darren Tucker261d93a2010-04-09 18:13:27 +1000206int utmpx_get_entry(struct logininfo *li);
andre2ff7b5d2000-06-03 14:57:40 +0000207int wtmp_get_entry(struct logininfo *li);
208int wtmpx_get_entry(struct logininfo *li);
209
Darren Tucker691d5232005-02-15 21:45:57 +1100210extern Buffer loginmsg;
211
andre6bb92372000-06-19 08:20:03 +0000212/* pick the shortest string */
Damien Miller8899ed32004-09-12 15:18:55 +1000213#define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2))
andre6bb92372000-06-19 08:20:03 +0000214
andre2ff7b5d2000-06-03 14:57:40 +0000215/**
216 ** platform-independent login functions
217 **/
218
Damien Miller8899ed32004-09-12 15:18:55 +1000219/*
220 * login_login(struct logininfo *) - Record a login
Kevin Stevesef4eea92001-02-05 12:42:17 +0000221 *
andre6bb92372000-06-19 08:20:03 +0000222 * Call with a pointer to a struct logininfo initialised with
223 * login_init_entry() or login_alloc_entry()
224 *
225 * Returns:
226 * >0 if successful
227 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
228 */
andre61e67252000-06-04 17:07:49 +0000229int
Damien Miller8899ed32004-09-12 15:18:55 +1000230login_login(struct logininfo *li)
andre61e67252000-06-04 17:07:49 +0000231{
232 li->type = LTYPE_LOGIN;
Damien Miller8899ed32004-09-12 15:18:55 +1000233 return (login_write(li));
andre61e67252000-06-04 17:07:49 +0000234}
235
236
Damien Miller8899ed32004-09-12 15:18:55 +1000237/*
238 * login_logout(struct logininfo *) - Record a logout
andre6bb92372000-06-19 08:20:03 +0000239 *
240 * Call as with login_login()
241 *
242 * Returns:
243 * >0 if successful
244 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
245 */
andre61e67252000-06-04 17:07:49 +0000246int
247login_logout(struct logininfo *li)
248{
249 li->type = LTYPE_LOGOUT;
Damien Miller8899ed32004-09-12 15:18:55 +1000250 return (login_write(li));
andre61e67252000-06-04 17:07:49 +0000251}
252
Damien Miller8899ed32004-09-12 15:18:55 +1000253/*
254 * login_get_lastlog_time(int) - Retrieve the last login time
andre6bb92372000-06-19 08:20:03 +0000255 *
256 * Retrieve the last login time for the given uid. Will try to use the
257 * system lastlog facilities if they are available, but will fall back
258 * to looking in wtmp/wtmpx if necessary
259 *
260 * Returns:
261 * 0 on failure, or if user has never logged in
262 * Time in seconds from the epoch if successful
263 *
264 * Useful preprocessor symbols:
265 * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
266 * info
267 * USE_LASTLOG: If set, indicates the presence of system lastlog
268 * facilities. If this and DISABLE_LASTLOG are not set,
269 * try to retrieve lastlog information from wtmp/wtmpx.
270 */
andre61e67252000-06-04 17:07:49 +0000271unsigned int
Damien Miller34ee4202010-11-05 10:52:37 +1100272login_get_lastlog_time(const uid_t uid)
andre61e67252000-06-04 17:07:49 +0000273{
274 struct logininfo li;
275
andre6bb92372000-06-19 08:20:03 +0000276 if (login_get_lastlog(&li, uid))
Damien Miller8899ed32004-09-12 15:18:55 +1000277 return (li.tv_sec);
andre6bb92372000-06-19 08:20:03 +0000278 else
Damien Miller8899ed32004-09-12 15:18:55 +1000279 return (0);
andre61e67252000-06-04 17:07:49 +0000280}
281
Damien Miller8899ed32004-09-12 15:18:55 +1000282/*
283 * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
andre6bb92372000-06-19 08:20:03 +0000284 *
285 * Retrieve a logininfo structure populated (only partially) with
286 * information from the system lastlog data, or from wtmp/wtmpx if no
287 * system lastlog information exists.
288 *
289 * Note this routine must be given a pre-allocated logininfo.
290 *
291 * Returns:
292 * >0: A pointer to your struct logininfo if successful
293 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
andre6bb92372000-06-19 08:20:03 +0000294 */
andre61e67252000-06-04 17:07:49 +0000295struct logininfo *
Damien Miller34ee4202010-11-05 10:52:37 +1100296login_get_lastlog(struct logininfo *li, const uid_t uid)
andre61e67252000-06-04 17:07:49 +0000297{
andre6bb92372000-06-19 08:20:03 +0000298 struct passwd *pw;
andre6bb92372000-06-19 08:20:03 +0000299
Damien Miller348c9b72000-08-15 10:01:22 +1000300 memset(li, '\0', sizeof(*li));
andre61e67252000-06-04 17:07:49 +0000301 li->uid = uid;
andre6bb92372000-06-19 08:20:03 +0000302
Kevin Stevesef4eea92001-02-05 12:42:17 +0000303 /*
Damien Miller53c5d462000-06-28 00:50:50 +1000304 * If we don't have a 'real' lastlog, we need the username to
andre6bb92372000-06-19 08:20:03 +0000305 * reliably search wtmp(x) for the last login (see
Kevin Stevesef4eea92001-02-05 12:42:17 +0000306 * wtmp_get_entry().)
Damien Miller53c5d462000-06-28 00:50:50 +1000307 */
andre6bb92372000-06-19 08:20:03 +0000308 pw = getpwuid(uid);
Damien Millerdd47aa22000-06-27 11:18:27 +1000309 if (pw == NULL)
Damien Miller34ee4202010-11-05 10:52:37 +1100310 fatal("%s: Cannot find account for uid %ld", __func__,
311 (long)uid);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000312
Damien Miller7d97fd92013-12-29 17:40:18 +1100313 if (strlcpy(li->username, pw->pw_name, sizeof(li->username)) >=
314 sizeof(li->username)) {
315 error("%s: username too long (%lu > max %lu)", __func__,
Darren Tucker1c4a0112014-01-17 12:23:23 +1100316 (unsigned long)strlen(pw->pw_name),
317 (unsigned long)sizeof(li->username) - 1);
Damien Miller7d97fd92013-12-29 17:40:18 +1100318 return NULL;
319 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000320
andre61e67252000-06-04 17:07:49 +0000321 if (getlast_entry(li))
Damien Miller8899ed32004-09-12 15:18:55 +1000322 return (li);
andre61e67252000-06-04 17:07:49 +0000323 else
Damien Miller8899ed32004-09-12 15:18:55 +1000324 return (NULL);
andre61e67252000-06-04 17:07:49 +0000325}
326
Damien Miller8899ed32004-09-12 15:18:55 +1000327/*
328 * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise
Kevin Stevesef4eea92001-02-05 12:42:17 +0000329 * a logininfo structure
330 *
andre6bb92372000-06-19 08:20:03 +0000331 * This function creates a new struct logininfo, a data structure
332 * meant to carry the information required to portably record login info.
333 *
334 * Returns a pointer to a newly created struct logininfo. If memory
335 * allocation fails, the program halts.
336 */
andre61e67252000-06-04 17:07:49 +0000337struct
Damien Miller34ee4202010-11-05 10:52:37 +1100338logininfo *login_alloc_entry(pid_t pid, const char *username,
Damien Miller8899ed32004-09-12 15:18:55 +1000339 const char *hostname, const char *line)
andre61e67252000-06-04 17:07:49 +0000340{
andre2ff7b5d2000-06-03 14:57:40 +0000341 struct logininfo *newli;
342
Damien Miller8899ed32004-09-12 15:18:55 +1000343 newli = xmalloc(sizeof(*newli));
344 login_init_entry(newli, pid, username, hostname, line);
345 return (newli);
andre61e67252000-06-04 17:07:49 +0000346}
andre2ff7b5d2000-06-03 14:57:40 +0000347
348
andre6bb92372000-06-19 08:20:03 +0000349/* login_free_entry(struct logininfo *) - free struct memory */
andre61e67252000-06-04 17:07:49 +0000350void
351login_free_entry(struct logininfo *li)
352{
Darren Tuckerf60845f2013-06-02 08:07:31 +1000353 free(li);
andre61e67252000-06-04 17:07:49 +0000354}
355
andre2ff7b5d2000-06-03 14:57:40 +0000356
andre6bb92372000-06-19 08:20:03 +0000357/* login_init_entry(struct logininfo *, int, char*, char*, char*)
358 * - initialise a struct logininfo
Kevin Stevesef4eea92001-02-05 12:42:17 +0000359 *
andre6bb92372000-06-19 08:20:03 +0000360 * Populates a new struct logininfo, a data structure meant to carry
361 * the information required to portably record login info.
362 *
363 * Returns: 1
364 */
andre61e67252000-06-04 17:07:49 +0000365int
Damien Miller34ee4202010-11-05 10:52:37 +1100366login_init_entry(struct logininfo *li, pid_t pid, const char *username,
Damien Miller8899ed32004-09-12 15:18:55 +1000367 const char *hostname, const char *line)
andre61e67252000-06-04 17:07:49 +0000368{
Damien Millerf8af08d2000-06-27 09:40:06 +1000369 struct passwd *pw;
Kevin Stevesef4eea92001-02-05 12:42:17 +0000370
Damien Miller348c9b72000-08-15 10:01:22 +1000371 memset(li, 0, sizeof(*li));
Kevin Stevesef4eea92001-02-05 12:42:17 +0000372
andre61e67252000-06-04 17:07:49 +0000373 li->pid = pid;
Damien Millerf8af08d2000-06-27 09:40:06 +1000374
andre2ff7b5d2000-06-03 14:57:40 +0000375 /* set the line information */
andre61e67252000-06-04 17:07:49 +0000376 if (line)
andre2ff7b5d2000-06-03 14:57:40 +0000377 line_fullname(li->line, line, sizeof(li->line));
andre2ff7b5d2000-06-03 14:57:40 +0000378
Damien Millerf8af08d2000-06-27 09:40:06 +1000379 if (username) {
andre2ff7b5d2000-06-03 14:57:40 +0000380 strlcpy(li->username, username, sizeof(li->username));
Damien Millerf8af08d2000-06-27 09:40:06 +1000381 pw = getpwnam(li->username);
Damien Miller8899ed32004-09-12 15:18:55 +1000382 if (pw == NULL) {
Damien Miller94cf4c82005-07-17 17:04:47 +1000383 fatal("%s: Cannot find user \"%s\"", __func__,
Damien Miller8899ed32004-09-12 15:18:55 +1000384 li->username);
385 }
Damien Millerf8af08d2000-06-27 09:40:06 +1000386 li->uid = pw->pw_uid;
387 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000388
andre61e67252000-06-04 17:07:49 +0000389 if (hostname)
andre2ff7b5d2000-06-03 14:57:40 +0000390 strlcpy(li->hostname, hostname, sizeof(li->hostname));
Damien Millerf8af08d2000-06-27 09:40:06 +1000391
Damien Miller8899ed32004-09-12 15:18:55 +1000392 return (1);
andre2ff7b5d2000-06-03 14:57:40 +0000393}
394
Damien Miller94cf4c82005-07-17 17:04:47 +1000395/*
Damien Miller8899ed32004-09-12 15:18:55 +1000396 * login_set_current_time(struct logininfo *) - set the current time
andre6bb92372000-06-19 08:20:03 +0000397 *
398 * Set the current time in a logininfo structure. This function is
399 * meant to eliminate the need to deal with system dependencies for
400 * time handling.
401 */
andre2ff7b5d2000-06-03 14:57:40 +0000402void
andre61e67252000-06-04 17:07:49 +0000403login_set_current_time(struct logininfo *li)
404{
andre2ff7b5d2000-06-03 14:57:40 +0000405 struct timeval tv;
406
407 gettimeofday(&tv, NULL);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000408
Damien Millerf8af08d2000-06-27 09:40:06 +1000409 li->tv_sec = tv.tv_sec;
410 li->tv_usec = tv.tv_usec;
andre2ff7b5d2000-06-03 14:57:40 +0000411}
412
andre61e67252000-06-04 17:07:49 +0000413/* copy a sockaddr_* into our logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000414void
andre61e67252000-06-04 17:07:49 +0000415login_set_addr(struct logininfo *li, const struct sockaddr *sa,
Damien Miller8899ed32004-09-12 15:18:55 +1000416 const unsigned int sa_size)
andre61e67252000-06-04 17:07:49 +0000417{
418 unsigned int bufsize = sa_size;
419
420 /* make sure we don't overrun our union */
421 if (sizeof(li->hostaddr) < sa_size)
422 bufsize = sizeof(li->hostaddr);
423
Damien Miller8899ed32004-09-12 15:18:55 +1000424 memcpy(&li->hostaddr.sa, sa, bufsize);
andre2ff7b5d2000-06-03 14:57:40 +0000425}
426
andre2ff7b5d2000-06-03 14:57:40 +0000427
andre61e67252000-06-04 17:07:49 +0000428/**
429 ** login_write: Call low-level recording functions based on autoconf
430 ** results
431 **/
andre2ff7b5d2000-06-03 14:57:40 +0000432int
Damien Miller8899ed32004-09-12 15:18:55 +1000433login_write(struct logininfo *li)
andre61e67252000-06-04 17:07:49 +0000434{
Damien Millerbac2d8a2000-09-05 16:13:06 +1100435#ifndef HAVE_CYGWIN
Damien Miller8899ed32004-09-12 15:18:55 +1000436 if (geteuid() != 0) {
437 logit("Attempt to write login records by non-root user (aborting)");
438 return (1);
andre2ff7b5d2000-06-03 14:57:40 +0000439 }
Damien Millerbac2d8a2000-09-05 16:13:06 +1100440#endif
Damien Millerdd47aa22000-06-27 11:18:27 +1000441
andre2ff7b5d2000-06-03 14:57:40 +0000442 /* set the timestamp */
443 login_set_current_time(li);
444#ifdef USE_LOGIN
445 syslogin_write_entry(li);
446#endif
447#ifdef USE_LASTLOG
Damien Miller8899ed32004-09-12 15:18:55 +1000448 if (li->type == LTYPE_LOGIN)
andre2ff7b5d2000-06-03 14:57:40 +0000449 lastlog_write_entry(li);
andre2ff7b5d2000-06-03 14:57:40 +0000450#endif
451#ifdef USE_UTMP
452 utmp_write_entry(li);
453#endif
454#ifdef USE_WTMP
455 wtmp_write_entry(li);
456#endif
457#ifdef USE_UTMPX
458 utmpx_write_entry(li);
459#endif
460#ifdef USE_WTMPX
461 wtmpx_write_entry(li);
462#endif
Darren Tucker397a2f22004-08-15 00:09:11 +1000463#ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN
Damien Miller94cf4c82005-07-17 17:04:47 +1000464 if (li->type == LTYPE_LOGIN &&
Damien Millerb6f72f52005-07-17 17:26:43 +1000465 !sys_auth_record_login(li->username,li->hostname,li->line,
466 &loginmsg))
Darren Tucker397a2f22004-08-15 00:09:11 +1000467 logit("Writing login record failed for %s", li->username);
468#endif
Darren Tucker2e0cf0d2005-02-08 21:52:47 +1100469#ifdef SSH_AUDIT_EVENTS
Darren Tucker269a1ea2005-02-03 00:20:53 +1100470 if (li->type == LTYPE_LOGIN)
Darren Tuckerea52a822011-01-17 21:15:27 +1100471 audit_session_open(li);
Darren Tucker269a1ea2005-02-03 00:20:53 +1100472 else if (li->type == LTYPE_LOGOUT)
Darren Tuckerea52a822011-01-17 21:15:27 +1100473 audit_session_close(li);
Darren Tucker269a1ea2005-02-03 00:20:53 +1100474#endif
Damien Miller8899ed32004-09-12 15:18:55 +1000475 return (0);
andre2ff7b5d2000-06-03 14:57:40 +0000476}
477
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000478#ifdef LOGIN_NEEDS_UTMPX
479int
480login_utmp_only(struct logininfo *li)
481{
Damien Millera8e06ce2003-11-21 23:48:55 +1100482 li->type = LTYPE_LOGIN;
Ben Lindstrom9197c592001-10-26 15:56:55 +0000483 login_set_current_time(li);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000484# ifdef USE_UTMP
485 utmp_write_entry(li);
486# endif
487# ifdef USE_WTMP
488 wtmp_write_entry(li);
489# endif
490# ifdef USE_UTMPX
491 utmpx_write_entry(li);
492# endif
493# ifdef USE_WTMPX
494 wtmpx_write_entry(li);
495# endif
Damien Miller8899ed32004-09-12 15:18:55 +1000496 return (0);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000497}
498#endif
499
andre2ff7b5d2000-06-03 14:57:40 +0000500/**
andre61e67252000-06-04 17:07:49 +0000501 ** getlast_entry: Call low-level functions to retrieve the last login
502 ** time.
andre2ff7b5d2000-06-03 14:57:40 +0000503 **/
504
andre61e67252000-06-04 17:07:49 +0000505/* take the uid in li and return the last login time */
506int
507getlast_entry(struct logininfo *li)
508{
509#ifdef USE_LASTLOG
Damien Miller53c5d462000-06-28 00:50:50 +1000510 return(lastlog_get_entry(li));
Damien Millerdd47aa22000-06-27 11:18:27 +1000511#else /* !USE_LASTLOG */
Darren Tucker261d93a2010-04-09 18:13:27 +1000512#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
513 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
514 return (utmpx_get_entry(li));
515#endif
andre61e67252000-06-04 17:07:49 +0000516
Damien Miller8899ed32004-09-12 15:18:55 +1000517#if defined(DISABLE_LASTLOG)
Kevin Stevesef4eea92001-02-05 12:42:17 +0000518 /* On some systems we shouldn't even try to obtain last login
andreecaabf12000-06-12 22:21:44 +0000519 * time, e.g. AIX */
Damien Miller8899ed32004-09-12 15:18:55 +1000520 return (0);
521# elif defined(USE_WTMP) && \
522 (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
andre61e67252000-06-04 17:07:49 +0000523 /* retrieve last login time from utmp */
Damien Millerdd47aa22000-06-27 11:18:27 +1000524 return (wtmp_get_entry(li));
Damien Miller8899ed32004-09-12 15:18:55 +1000525# elif defined(USE_WTMPX) && \
526 (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
andre61e67252000-06-04 17:07:49 +0000527 /* If wtmp isn't available, try wtmpx */
Damien Millerdd47aa22000-06-27 11:18:27 +1000528 return (wtmpx_get_entry(li));
Damien Miller8899ed32004-09-12 15:18:55 +1000529# else
andre61e67252000-06-04 17:07:49 +0000530 /* Give up: No means of retrieving last login time */
Damien Miller8899ed32004-09-12 15:18:55 +1000531 return (0);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000532# endif /* DISABLE_LASTLOG */
Damien Millerdd47aa22000-06-27 11:18:27 +1000533#endif /* USE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000534}
535
536
537
andre2ff7b5d2000-06-03 14:57:40 +0000538/*
andre61e67252000-06-04 17:07:49 +0000539 * 'line' string utility functions
540 *
541 * These functions process the 'line' string into one of three forms:
542 *
andre2ff7b5d2000-06-03 14:57:40 +0000543 * 1. The full filename (including '/dev')
544 * 2. The stripped name (excluding '/dev')
andre61e67252000-06-04 17:07:49 +0000545 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
546 * /dev/pts/1 -> ts/1 )
andre2ff7b5d2000-06-03 14:57:40 +0000547 *
548 * Form 3 is used on some systems to identify a .tmp.? entry when
549 * attempting to remove it. Typically both addition and removal is
andre61e67252000-06-04 17:07:49 +0000550 * performed by one application - say, sshd - so as long as the choice
551 * uniquely identifies a terminal it's ok.
andre2ff7b5d2000-06-03 14:57:40 +0000552 */
553
554
Damien Miller8899ed32004-09-12 15:18:55 +1000555/*
556 * line_fullname(): add the leading '/dev/' if it doesn't exist make
557 * sure dst has enough space, if not just copy src (ugh)
558 */
andre2ff7b5d2000-06-03 14:57:40 +0000559char *
Damien Miller52c8afe2005-06-19 10:19:43 +1000560line_fullname(char *dst, const char *src, u_int dstsize)
andre61e67252000-06-04 17:07:49 +0000561{
andre2ff7b5d2000-06-03 14:57:40 +0000562 memset(dst, '\0', dstsize);
Damien Miller8899ed32004-09-12 15:18:55 +1000563 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
andre2ff7b5d2000-06-03 14:57:40 +0000564 strlcpy(dst, src, dstsize);
Damien Miller8899ed32004-09-12 15:18:55 +1000565 else {
Damien Miller1a132252000-06-13 21:23:17 +1000566 strlcpy(dst, "/dev/", dstsize);
andre2ff7b5d2000-06-03 14:57:40 +0000567 strlcat(dst, src, dstsize);
568 }
Damien Miller8899ed32004-09-12 15:18:55 +1000569 return (dst);
andre2ff7b5d2000-06-03 14:57:40 +0000570}
571
andre61e67252000-06-04 17:07:49 +0000572/* line_stripname(): strip the leading '/dev' if it exists, return dst */
andre2ff7b5d2000-06-03 14:57:40 +0000573char *
andre61e67252000-06-04 17:07:49 +0000574line_stripname(char *dst, const char *src, int dstsize)
575{
andre2ff7b5d2000-06-03 14:57:40 +0000576 memset(dst, '\0', dstsize);
577 if (strncmp(src, "/dev/", 5) == 0)
Damien Millerf5a81472000-09-30 21:34:44 +1100578 strlcpy(dst, src + 5, dstsize);
andre2ff7b5d2000-06-03 14:57:40 +0000579 else
580 strlcpy(dst, src, dstsize);
Damien Miller8899ed32004-09-12 15:18:55 +1000581 return (dst);
andre61e67252000-06-04 17:07:49 +0000582}
583
Damien Miller94cf4c82005-07-17 17:04:47 +1000584/*
Damien Miller8899ed32004-09-12 15:18:55 +1000585 * line_abbrevname(): Return the abbreviated (usually four-character)
andre61e67252000-06-04 17:07:49 +0000586 * form of the line (Just use the last <dstsize> characters of the
587 * full name.)
588 *
589 * NOTE: use strncpy because we do NOT necessarily want zero
Damien Miller8899ed32004-09-12 15:18:55 +1000590 * termination
591 */
andre2ff7b5d2000-06-03 14:57:40 +0000592char *
Kevin Stevesef4eea92001-02-05 12:42:17 +0000593line_abbrevname(char *dst, const char *src, int dstsize)
Damien Millerdd47aa22000-06-27 11:18:27 +1000594{
595 size_t len;
Kevin Stevesef4eea92001-02-05 12:42:17 +0000596
andre2ff7b5d2000-06-03 14:57:40 +0000597 memset(dst, '\0', dstsize);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000598
Damien Miller8e81ed32000-07-01 13:17:42 +1000599 /* Always skip prefix if present */
600 if (strncmp(src, "/dev/", 5) == 0)
601 src += 5;
Kevin Stevesef4eea92001-02-05 12:42:17 +0000602
Damien Millerf1b9d112002-04-23 23:09:19 +1000603#ifdef WITH_ABBREV_NO_TTY
604 if (strncmp(src, "tty", 3) == 0)
605 src += 3;
606#endif
607
Damien Millerdd47aa22000-06-27 11:18:27 +1000608 len = strlen(src);
609
Damien Miller8e81ed32000-07-01 13:17:42 +1000610 if (len > 0) {
611 if (((int)len - dstsize) > 0)
612 src += ((int)len - dstsize);
613
614 /* note: _don't_ change this to strlcpy */
Kevin Stevesef4eea92001-02-05 12:42:17 +0000615 strncpy(dst, src, (size_t)dstsize);
Damien Millerdd47aa22000-06-27 11:18:27 +1000616 }
Kevin Stevesef4eea92001-02-05 12:42:17 +0000617
Damien Miller8899ed32004-09-12 15:18:55 +1000618 return (dst);
andre2ff7b5d2000-06-03 14:57:40 +0000619}
620
andre2ff7b5d2000-06-03 14:57:40 +0000621/**
622 ** utmp utility functions
andre61e67252000-06-04 17:07:49 +0000623 **
624 ** These functions manipulate struct utmp, taking system differences
625 ** into account.
andre2ff7b5d2000-06-03 14:57:40 +0000626 **/
627
628#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
629
andre2ff7b5d2000-06-03 14:57:40 +0000630/* build the utmp structure */
631void
andre61e67252000-06-04 17:07:49 +0000632set_utmp_time(struct logininfo *li, struct utmp *ut)
633{
Damien Miller8899ed32004-09-12 15:18:55 +1000634# if defined(HAVE_TV_IN_UTMP)
andre2ff7b5d2000-06-03 14:57:40 +0000635 ut->ut_tv.tv_sec = li->tv_sec;
636 ut->ut_tv.tv_usec = li->tv_usec;
Damien Miller8899ed32004-09-12 15:18:55 +1000637# elif defined(HAVE_TIME_IN_UTMP)
andre2ff7b5d2000-06-03 14:57:40 +0000638 ut->ut_time = li->tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000639# endif
andre2ff7b5d2000-06-03 14:57:40 +0000640}
641
642void
643construct_utmp(struct logininfo *li,
andre61e67252000-06-04 17:07:49 +0000644 struct utmp *ut)
645{
Damien Miller02e16ad2003-01-03 14:42:27 +1100646# ifdef HAVE_ADDR_V6_IN_UTMP
647 struct sockaddr_in6 *sa6;
Damien Miller8899ed32004-09-12 15:18:55 +1000648# endif
649
Damien Miller348c9b72000-08-15 10:01:22 +1000650 memset(ut, '\0', sizeof(*ut));
andre6bb92372000-06-19 08:20:03 +0000651
652 /* First fill out fields used for both logins and logouts */
653
Damien Millerdd47aa22000-06-27 11:18:27 +1000654# ifdef HAVE_ID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000655 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000656# endif
andre2ff7b5d2000-06-03 14:57:40 +0000657
Damien Millerdd47aa22000-06-27 11:18:27 +1000658# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +0000659 /* This is done here to keep utmp constants out of struct logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000660 switch (li->type) {
661 case LTYPE_LOGIN:
662 ut->ut_type = USER_PROCESS;
Tim Rice81ed5182002-09-25 17:38:46 -0700663#ifdef _UNICOS
Ben Lindstrom6db66ff2001-08-06 23:29:16 +0000664 cray_set_tmpdir(ut);
665#endif
andre2ff7b5d2000-06-03 14:57:40 +0000666 break;
667 case LTYPE_LOGOUT:
668 ut->ut_type = DEAD_PROCESS;
Tim Rice81ed5182002-09-25 17:38:46 -0700669#ifdef _UNICOS
Ben Lindstrom6db66ff2001-08-06 23:29:16 +0000670 cray_retain_utmp(ut, li->pid);
671#endif
andre2ff7b5d2000-06-03 14:57:40 +0000672 break;
673 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000674# endif
andre6bb92372000-06-19 08:20:03 +0000675 set_utmp_time(li, ut);
andre2ff7b5d2000-06-03 14:57:40 +0000676
andre6bb92372000-06-19 08:20:03 +0000677 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000678
679# ifdef HAVE_PID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000680 ut->ut_pid = li->pid;
Damien Millerdd47aa22000-06-27 11:18:27 +1000681# endif
andre6bb92372000-06-19 08:20:03 +0000682
683 /* If we're logging out, leave all other fields blank */
684 if (li->type == LTYPE_LOGOUT)
Damien Miller8899ed32004-09-12 15:18:55 +1000685 return;
andre6bb92372000-06-19 08:20:03 +0000686
Damien Millerdd47aa22000-06-27 11:18:27 +1000687 /*
688 * These fields are only used when logging in, and are blank
Kevin Stevesef4eea92001-02-05 12:42:17 +0000689 * for logouts.
Damien Millerdd47aa22000-06-27 11:18:27 +1000690 */
andre6bb92372000-06-19 08:20:03 +0000691
692 /* Use strncpy because we don't necessarily want null termination */
Damien Miller8899ed32004-09-12 15:18:55 +1000693 strncpy(ut->ut_name, li->username,
694 MIN_SIZEOF(ut->ut_name, li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000695# ifdef HAVE_HOST_IN_UTMP
Damien Miller8899ed32004-09-12 15:18:55 +1000696 strncpy(ut->ut_host, li->hostname,
697 MIN_SIZEOF(ut->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000698# endif
699# ifdef HAVE_ADDR_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000700 /* this is just a 32-bit IP address */
701 if (li->hostaddr.sa.sa_family == AF_INET)
702 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
Kevin Stevesef4eea92001-02-05 12:42:17 +0000703# endif
Damien Miller02e16ad2003-01-03 14:42:27 +1100704# ifdef HAVE_ADDR_V6_IN_UTMP
705 /* this is just a 128-bit IPv6 address */
706 if (li->hostaddr.sa.sa_family == AF_INET6) {
707 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
708 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
709 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
710 ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
711 ut->ut_addr_v6[1] = 0;
712 ut->ut_addr_v6[2] = 0;
713 ut->ut_addr_v6[3] = 0;
714 }
715 }
716# endif
andre61e67252000-06-04 17:07:49 +0000717}
Damien Millerdd47aa22000-06-27 11:18:27 +1000718#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
andre61e67252000-06-04 17:07:49 +0000719
andre2ff7b5d2000-06-03 14:57:40 +0000720/**
721 ** utmpx utility functions
andre61e67252000-06-04 17:07:49 +0000722 **
723 ** These functions manipulate struct utmpx, accounting for system
724 ** variations.
andre2ff7b5d2000-06-03 14:57:40 +0000725 **/
726
727#if defined(USE_UTMPX) || defined (USE_WTMPX)
andre2ff7b5d2000-06-03 14:57:40 +0000728/* build the utmpx structure */
729void
andre61e67252000-06-04 17:07:49 +0000730set_utmpx_time(struct logininfo *li, struct utmpx *utx)
731{
Damien Miller8899ed32004-09-12 15:18:55 +1000732# if defined(HAVE_TV_IN_UTMPX)
andre2ff7b5d2000-06-03 14:57:40 +0000733 utx->ut_tv.tv_sec = li->tv_sec;
734 utx->ut_tv.tv_usec = li->tv_usec;
Damien Miller8899ed32004-09-12 15:18:55 +1000735# elif defined(HAVE_TIME_IN_UTMPX)
andre2ff7b5d2000-06-03 14:57:40 +0000736 utx->ut_time = li->tv_sec;
Damien Miller8899ed32004-09-12 15:18:55 +1000737# endif
andre2ff7b5d2000-06-03 14:57:40 +0000738}
739
andre61e67252000-06-04 17:07:49 +0000740void
741construct_utmpx(struct logininfo *li, struct utmpx *utx)
742{
Damien Miller02e16ad2003-01-03 14:42:27 +1100743# ifdef HAVE_ADDR_V6_IN_UTMP
744 struct sockaddr_in6 *sa6;
745# endif
Damien Miller348c9b72000-08-15 10:01:22 +1000746 memset(utx, '\0', sizeof(*utx));
Damien Miller8899ed32004-09-12 15:18:55 +1000747
Damien Miller8e81ed32000-07-01 13:17:42 +1000748# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000749 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
Damien Miller8e81ed32000-07-01 13:17:42 +1000750# endif
andre2ff7b5d2000-06-03 14:57:40 +0000751
752 /* this is done here to keep utmp constants out of loginrec.h */
753 switch (li->type) {
754 case LTYPE_LOGIN:
755 utx->ut_type = USER_PROCESS;
756 break;
757 case LTYPE_LOGOUT:
758 utx->ut_type = DEAD_PROCESS;
759 break;
760 }
andre2ff7b5d2000-06-03 14:57:40 +0000761 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
andre2ff7b5d2000-06-03 14:57:40 +0000762 set_utmpx_time(li, utx);
andre6bb92372000-06-19 08:20:03 +0000763 utx->ut_pid = li->pid;
Damien Miller8899ed32004-09-12 15:18:55 +1000764
Tim Ricee06ae4a2002-02-24 17:56:46 -0800765 /* strncpy(): Don't necessarily want null termination */
Darren Tucker0b8a2262010-01-09 18:18:04 +1100766 strncpy(utx->ut_user, li->username,
767 MIN_SIZEOF(utx->ut_user, li->username));
andre6bb92372000-06-19 08:20:03 +0000768
769 if (li->type == LTYPE_LOGOUT)
770 return;
771
Damien Millerdd47aa22000-06-27 11:18:27 +1000772 /*
773 * These fields are only used when logging in, and are blank
Kevin Stevesef4eea92001-02-05 12:42:17 +0000774 * for logouts.
Damien Millerdd47aa22000-06-27 11:18:27 +1000775 */
andre6bb92372000-06-19 08:20:03 +0000776
Damien Millerdd47aa22000-06-27 11:18:27 +1000777# ifdef HAVE_HOST_IN_UTMPX
Damien Miller8899ed32004-09-12 15:18:55 +1000778 strncpy(utx->ut_host, li->hostname,
779 MIN_SIZEOF(utx->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000780# endif
781# ifdef HAVE_ADDR_IN_UTMPX
Damien Millerd6f204d2000-09-23 13:57:27 +1100782 /* this is just a 32-bit IP address */
783 if (li->hostaddr.sa.sa_family == AF_INET)
784 utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
Damien Millerdd47aa22000-06-27 11:18:27 +1000785# endif
Damien Miller02e16ad2003-01-03 14:42:27 +1100786# ifdef HAVE_ADDR_V6_IN_UTMP
787 /* this is just a 128-bit IPv6 address */
788 if (li->hostaddr.sa.sa_family == AF_INET6) {
789 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
790 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
791 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
792 ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
793 ut->ut_addr_v6[1] = 0;
794 ut->ut_addr_v6[2] = 0;
795 ut->ut_addr_v6[3] = 0;
796 }
797 }
798# endif
Damien Millerdd47aa22000-06-27 11:18:27 +1000799# ifdef HAVE_SYSLEN_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +0000800 /* ut_syslen is the length of the utx_host string */
801 utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +1000802# endif
andre61e67252000-06-04 17:07:49 +0000803}
Damien Millerdd47aa22000-06-27 11:18:27 +1000804#endif /* USE_UTMPX || USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000805
806/**
andre61e67252000-06-04 17:07:49 +0000807 ** Low-level utmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000808 **/
809
810/* FIXME: (ATL) utmp_write_direct needs testing */
andre2ff7b5d2000-06-03 14:57:40 +0000811#ifdef USE_UTMP
812
andre2ff7b5d2000-06-03 14:57:40 +0000813/* if we can, use pututline() etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000814# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
815 defined(HAVE_PUTUTLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000816# define UTMP_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000817# endif
andre2ff7b5d2000-06-03 14:57:40 +0000818
819
820/* write a utmp entry with the system's help (pututline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000821# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000822static int
andre61e67252000-06-04 17:07:49 +0000823utmp_write_library(struct logininfo *li, struct utmp *ut)
824{
andre2ff7b5d2000-06-03 14:57:40 +0000825 setutent();
826 pututline(ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000827# ifdef HAVE_ENDUTENT
andre2ff7b5d2000-06-03 14:57:40 +0000828 endutent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000829# endif
Damien Miller8899ed32004-09-12 15:18:55 +1000830 return (1);
andre61e67252000-06-04 17:07:49 +0000831}
Damien Millerdd47aa22000-06-27 11:18:27 +1000832# else /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000833
Damien Miller94cf4c82005-07-17 17:04:47 +1000834/*
Damien Miller8899ed32004-09-12 15:18:55 +1000835 * Write a utmp entry direct to the file
836 * This is a slightly modification of code in OpenBSD's login.c
837 */
andre2ff7b5d2000-06-03 14:57:40 +0000838static int
andre61e67252000-06-04 17:07:49 +0000839utmp_write_direct(struct logininfo *li, struct utmp *ut)
840{
andre2ff7b5d2000-06-03 14:57:40 +0000841 struct utmp old_ut;
842 register int fd;
843 int tty;
844
andre6bb92372000-06-19 08:20:03 +0000845 /* FIXME: (ATL) ttyslot() needs local implementation */
Damien Miller348c9b72000-08-15 10:01:22 +1000846
Damien Millere5192fa2000-08-29 14:30:37 +1100847#if defined(HAVE_GETTTYENT)
Damien Miller8899ed32004-09-12 15:18:55 +1000848 struct ttyent *ty;
Damien Miller348c9b72000-08-15 10:01:22 +1000849
850 tty=0;
Damien Miller348c9b72000-08-15 10:01:22 +1000851 setttyent();
Damien Miller8899ed32004-09-12 15:18:55 +1000852 while (NULL != (ty = getttyent())) {
Damien Miller348c9b72000-08-15 10:01:22 +1000853 tty++;
854 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
855 break;
856 }
857 endttyent();
858
Damien Miller8899ed32004-09-12 15:18:55 +1000859 if (NULL == ty) {
Damien Miller81409592004-08-15 19:12:52 +1000860 logit("%s: tty not found", __func__);
861 return (0);
Damien Miller348c9b72000-08-15 10:01:22 +1000862 }
863#else /* FIXME */
864
andre2ff7b5d2000-06-03 14:57:40 +0000865 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
866
Damien Millere5192fa2000-08-29 14:30:37 +1100867#endif /* HAVE_GETTTYENT */
Damien Miller348c9b72000-08-15 10:01:22 +1000868
andre2ff7b5d2000-06-03 14:57:40 +0000869 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
Damien Miller81409592004-08-15 19:12:52 +1000870 off_t pos, ret;
871
872 pos = (off_t)tty * sizeof(struct utmp);
873 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
Damien Millerb0419f22004-08-23 21:53:28 +1000874 logit("%s: lseek: %s", __func__, strerror(errno));
Damien Miller4a06f922011-01-02 21:43:59 +1100875 close(fd);
Damien Miller81409592004-08-15 19:12:52 +1000876 return (0);
877 }
878 if (ret != pos) {
Damien Miller94cf4c82005-07-17 17:04:47 +1000879 logit("%s: Couldn't seek to tty %d slot in %s",
Damien Millerb0419f22004-08-23 21:53:28 +1000880 __func__, tty, UTMP_FILE);
Damien Miller4a06f922011-01-02 21:43:59 +1100881 close(fd);
Damien Miller81409592004-08-15 19:12:52 +1000882 return (0);
883 }
andre2ff7b5d2000-06-03 14:57:40 +0000884 /*
885 * Prevent luser from zero'ing out ut_host.
886 * If the new ut_line is empty but the old one is not
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000887 * and ut_line and ut_name match, preserve the old ut_line.
andre2ff7b5d2000-06-03 14:57:40 +0000888 */
Kevin Stevesef4eea92001-02-05 12:42:17 +0000889 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
Damien Miller8899ed32004-09-12 15:18:55 +1000890 (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
891 (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
892 (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0))
893 memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
Kevin Stevesef4eea92001-02-05 12:42:17 +0000894
Damien Miller81409592004-08-15 19:12:52 +1000895 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
Damien Millerb0419f22004-08-23 21:53:28 +1000896 logit("%s: lseek: %s", __func__, strerror(errno));
Damien Miller4a06f922011-01-02 21:43:59 +1100897 close(fd);
Damien Miller81409592004-08-15 19:12:52 +1000898 return (0);
899 }
900 if (ret != pos) {
Damien Millerb0419f22004-08-23 21:53:28 +1000901 logit("%s: Couldn't seek to tty %d slot in %s",
Damien Miller81409592004-08-15 19:12:52 +1000902 __func__, tty, UTMP_FILE);
Damien Miller4a06f922011-01-02 21:43:59 +1100903 close(fd);
Damien Miller81409592004-08-15 19:12:52 +1000904 return (0);
905 }
Damien Miller8899ed32004-09-12 15:18:55 +1000906 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
Damien Miller81409592004-08-15 19:12:52 +1000907 logit("%s: error writing %s: %s", __func__,
andre6bb92372000-06-19 08:20:03 +0000908 UTMP_FILE, strerror(errno));
Damien Miller4a06f922011-01-02 21:43:59 +1100909 close(fd);
910 return (0);
Damien Miller8899ed32004-09-12 15:18:55 +1000911 }
Kevin Stevesef4eea92001-02-05 12:42:17 +0000912
Damien Miller8899ed32004-09-12 15:18:55 +1000913 close(fd);
914 return (1);
Damien Miller53c5d462000-06-28 00:50:50 +1000915 } else {
Damien Miller8899ed32004-09-12 15:18:55 +1000916 return (0);
Damien Miller53c5d462000-06-28 00:50:50 +1000917 }
andre61e67252000-06-04 17:07:49 +0000918}
Damien Millerdd47aa22000-06-27 11:18:27 +1000919# endif /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000920
921static int
andre61e67252000-06-04 17:07:49 +0000922utmp_perform_login(struct logininfo *li)
923{
andre2ff7b5d2000-06-03 14:57:40 +0000924 struct utmp ut;
925
926 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000927# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000928 if (!utmp_write_library(li, &ut)) {
Damien Miller6b0279c2004-09-12 15:25:17 +1000929 logit("%s: utmp_write_library() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +1000930 return (0);
andre2ff7b5d2000-06-03 14:57:40 +0000931 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000932# else
andre2ff7b5d2000-06-03 14:57:40 +0000933 if (!utmp_write_direct(li, &ut)) {
Damien Miller6b0279c2004-09-12 15:25:17 +1000934 logit("%s: utmp_write_direct() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +1000935 return (0);
andre2ff7b5d2000-06-03 14:57:40 +0000936 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000937# endif
Damien Miller8899ed32004-09-12 15:18:55 +1000938 return (1);
andre61e67252000-06-04 17:07:49 +0000939}
andre2ff7b5d2000-06-03 14:57:40 +0000940
941
942static int
andre61e67252000-06-04 17:07:49 +0000943utmp_perform_logout(struct logininfo *li)
944{
andre2ff7b5d2000-06-03 14:57:40 +0000945 struct utmp ut;
946
andre6bb92372000-06-19 08:20:03 +0000947 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000948# ifdef UTMP_USE_LIBRARY
andre6bb92372000-06-19 08:20:03 +0000949 if (!utmp_write_library(li, &ut)) {
Damien Miller6b0279c2004-09-12 15:25:17 +1000950 logit("%s: utmp_write_library() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +1000951 return (0);
andre6bb92372000-06-19 08:20:03 +0000952 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000953# else
andre6bb92372000-06-19 08:20:03 +0000954 if (!utmp_write_direct(li, &ut)) {
Damien Miller6b0279c2004-09-12 15:25:17 +1000955 logit("%s: utmp_write_direct() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +1000956 return (0);
andre6bb92372000-06-19 08:20:03 +0000957 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000958# endif
Damien Miller8899ed32004-09-12 15:18:55 +1000959 return (1);
andre61e67252000-06-04 17:07:49 +0000960}
andre2ff7b5d2000-06-03 14:57:40 +0000961
962
963int
andre61e67252000-06-04 17:07:49 +0000964utmp_write_entry(struct logininfo *li)
965{
andre2ff7b5d2000-06-03 14:57:40 +0000966 switch(li->type) {
967 case LTYPE_LOGIN:
Damien Miller8899ed32004-09-12 15:18:55 +1000968 return (utmp_perform_login(li));
andre2ff7b5d2000-06-03 14:57:40 +0000969
970 case LTYPE_LOGOUT:
Damien Miller8899ed32004-09-12 15:18:55 +1000971 return (utmp_perform_logout(li));
andre2ff7b5d2000-06-03 14:57:40 +0000972
973 default:
Damien Miller6b0279c2004-09-12 15:25:17 +1000974 logit("%s: invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +1000975 return (0);
andre2ff7b5d2000-06-03 14:57:40 +0000976 }
andre61e67252000-06-04 17:07:49 +0000977}
Damien Millerdd47aa22000-06-27 11:18:27 +1000978#endif /* USE_UTMP */
andre2ff7b5d2000-06-03 14:57:40 +0000979
980
981/**
andre61e67252000-06-04 17:07:49 +0000982 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000983 **/
984
985/* not much point if we don't want utmpx entries */
986#ifdef USE_UTMPX
987
andre2ff7b5d2000-06-03 14:57:40 +0000988/* if we have the wherewithall, use pututxline etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000989# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
990 defined(HAVE_PUTUTXLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000991# define UTMPX_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000992# endif
andre2ff7b5d2000-06-03 14:57:40 +0000993
994
995/* write a utmpx entry with the system's help (pututxline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000996# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000997static int
andre61e67252000-06-04 17:07:49 +0000998utmpx_write_library(struct logininfo *li, struct utmpx *utx)
999{
andre2ff7b5d2000-06-03 14:57:40 +00001000 setutxent();
1001 pututxline(utx);
1002
Damien Millerdd47aa22000-06-27 11:18:27 +10001003# ifdef HAVE_ENDUTXENT
andre2ff7b5d2000-06-03 14:57:40 +00001004 endutxent();
Damien Millerdd47aa22000-06-27 11:18:27 +10001005# endif
Damien Miller8899ed32004-09-12 15:18:55 +10001006 return (1);
andre61e67252000-06-04 17:07:49 +00001007}
andre2ff7b5d2000-06-03 14:57:40 +00001008
Damien Millerdd47aa22000-06-27 11:18:27 +10001009# else /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +00001010
1011/* write a utmp entry direct to the file */
1012static int
andre61e67252000-06-04 17:07:49 +00001013utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
Kevin Stevesef4eea92001-02-05 12:42:17 +00001014{
Damien Miller6b0279c2004-09-12 15:25:17 +10001015 logit("%s: not implemented!", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001016 return (0);
andre61e67252000-06-04 17:07:49 +00001017}
Damien Millerdd47aa22000-06-27 11:18:27 +10001018# endif /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +00001019
1020static int
andre61e67252000-06-04 17:07:49 +00001021utmpx_perform_login(struct logininfo *li)
1022{
andre2ff7b5d2000-06-03 14:57:40 +00001023 struct utmpx utx;
1024
1025 construct_utmpx(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +10001026# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +00001027 if (!utmpx_write_library(li, &utx)) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001028 logit("%s: utmp_write_library() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001029 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001030 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001031# else
andre2ff7b5d2000-06-03 14:57:40 +00001032 if (!utmpx_write_direct(li, &ut)) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001033 logit("%s: utmp_write_direct() failed", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001034 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001035 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001036# endif
Damien Miller8899ed32004-09-12 15:18:55 +10001037 return (1);
andre61e67252000-06-04 17:07:49 +00001038}
andre2ff7b5d2000-06-03 14:57:40 +00001039
1040
1041static int
andre61e67252000-06-04 17:07:49 +00001042utmpx_perform_logout(struct logininfo *li)
1043{
andre2ff7b5d2000-06-03 14:57:40 +00001044 struct utmpx utx;
1045
Tim Ricee06ae4a2002-02-24 17:56:46 -08001046 construct_utmpx(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +10001047# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001048 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +10001049# endif
1050# ifdef HAVE_TYPE_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001051 utx.ut_type = DEAD_PROCESS;
Damien Millerdd47aa22000-06-27 11:18:27 +10001052# endif
andre2ff7b5d2000-06-03 14:57:40 +00001053
Damien Millerdd47aa22000-06-27 11:18:27 +10001054# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +00001055 utmpx_write_library(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +10001056# else
andre2ff7b5d2000-06-03 14:57:40 +00001057 utmpx_write_direct(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +10001058# endif
Damien Miller8899ed32004-09-12 15:18:55 +10001059 return (1);
andre61e67252000-06-04 17:07:49 +00001060}
andre2ff7b5d2000-06-03 14:57:40 +00001061
andre2ff7b5d2000-06-03 14:57:40 +00001062int
andre61e67252000-06-04 17:07:49 +00001063utmpx_write_entry(struct logininfo *li)
1064{
andre2ff7b5d2000-06-03 14:57:40 +00001065 switch(li->type) {
1066 case LTYPE_LOGIN:
Damien Miller8899ed32004-09-12 15:18:55 +10001067 return (utmpx_perform_login(li));
andre2ff7b5d2000-06-03 14:57:40 +00001068 case LTYPE_LOGOUT:
Damien Miller8899ed32004-09-12 15:18:55 +10001069 return (utmpx_perform_logout(li));
andre2ff7b5d2000-06-03 14:57:40 +00001070 default:
Damien Miller6b0279c2004-09-12 15:25:17 +10001071 logit("%s: invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001072 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001073 }
andre61e67252000-06-04 17:07:49 +00001074}
Damien Millerdd47aa22000-06-27 11:18:27 +10001075#endif /* USE_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001076
1077
1078/**
andre61e67252000-06-04 17:07:49 +00001079 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +00001080 **/
1081
Kevin Stevesef4eea92001-02-05 12:42:17 +00001082#ifdef USE_WTMP
andre2ff7b5d2000-06-03 14:57:40 +00001083
Damien Miller94cf4c82005-07-17 17:04:47 +10001084/*
Damien Miller8899ed32004-09-12 15:18:55 +10001085 * Write a wtmp entry direct to the end of the file
1086 * This is a slight modification of code in OpenBSD's logwtmp.c
1087 */
andre2ff7b5d2000-06-03 14:57:40 +00001088static int
andre61e67252000-06-04 17:07:49 +00001089wtmp_write(struct logininfo *li, struct utmp *ut)
1090{
andre2ff7b5d2000-06-03 14:57:40 +00001091 struct stat buf;
1092 int fd, ret = 1;
1093
1094 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001095 logit("%s: problem writing %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001096 WTMP_FILE, strerror(errno));
Damien Miller8899ed32004-09-12 15:18:55 +10001097 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001098 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001099 if (fstat(fd, &buf) == 0)
Darren Tucker8661b562003-07-06 15:20:46 +10001100 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
andre2ff7b5d2000-06-03 14:57:40 +00001101 ftruncate(fd, buf.st_size);
Damien Miller6b0279c2004-09-12 15:25:17 +10001102 logit("%s: problem writing %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001103 WTMP_FILE, strerror(errno));
1104 ret = 0;
1105 }
Damien Miller8899ed32004-09-12 15:18:55 +10001106 close(fd);
1107 return (ret);
andre61e67252000-06-04 17:07:49 +00001108}
andre2ff7b5d2000-06-03 14:57:40 +00001109
andre2ff7b5d2000-06-03 14:57:40 +00001110static int
Damien Millerdd47aa22000-06-27 11:18:27 +10001111wtmp_perform_login(struct logininfo *li)
1112{
andre2ff7b5d2000-06-03 14:57:40 +00001113 struct utmp ut;
1114
1115 construct_utmp(li, &ut);
Damien Miller8899ed32004-09-12 15:18:55 +10001116 return (wtmp_write(li, &ut));
andre61e67252000-06-04 17:07:49 +00001117}
andre2ff7b5d2000-06-03 14:57:40 +00001118
1119
1120static int
andre61e67252000-06-04 17:07:49 +00001121wtmp_perform_logout(struct logininfo *li)
1122{
andre2ff7b5d2000-06-03 14:57:40 +00001123 struct utmp ut;
1124
1125 construct_utmp(li, &ut);
Damien Miller8899ed32004-09-12 15:18:55 +10001126 return (wtmp_write(li, &ut));
andre61e67252000-06-04 17:07:49 +00001127}
andre2ff7b5d2000-06-03 14:57:40 +00001128
1129
1130int
andre61e67252000-06-04 17:07:49 +00001131wtmp_write_entry(struct logininfo *li)
1132{
andre2ff7b5d2000-06-03 14:57:40 +00001133 switch(li->type) {
1134 case LTYPE_LOGIN:
Damien Miller8899ed32004-09-12 15:18:55 +10001135 return (wtmp_perform_login(li));
andre2ff7b5d2000-06-03 14:57:40 +00001136 case LTYPE_LOGOUT:
Damien Miller8899ed32004-09-12 15:18:55 +10001137 return (wtmp_perform_logout(li));
andre2ff7b5d2000-06-03 14:57:40 +00001138 default:
Damien Miller6b0279c2004-09-12 15:25:17 +10001139 logit("%s: invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001140 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001141 }
andre61e67252000-06-04 17:07:49 +00001142}
andre2ff7b5d2000-06-03 14:57:40 +00001143
1144
Damien Miller94cf4c82005-07-17 17:04:47 +10001145/*
Damien Miller8899ed32004-09-12 15:18:55 +10001146 * Notes on fetching login data from wtmp/wtmpx
Kevin Stevesef4eea92001-02-05 12:42:17 +00001147 *
andre6bb92372000-06-19 08:20:03 +00001148 * Logouts are usually recorded with (amongst other things) a blank
1149 * username on a given tty line. However, some systems (HP-UX is one)
1150 * leave all fields set, but change the ut_type field to DEAD_PROCESS.
1151 *
1152 * Since we're only looking for logins here, we know that the username
1153 * must be set correctly. On systems that leave it in, we check for
1154 * ut_type==USER_PROCESS (indicating a login.)
1155 *
1156 * Portability: Some systems may set something other than USER_PROCESS
1157 * to indicate a login process. I don't know of any as I write. Also,
1158 * it's possible that some systems may both leave the username in
1159 * place and not have ut_type.
1160 */
1161
andre6bb92372000-06-19 08:20:03 +00001162/* return true if this wtmp entry indicates a login */
1163static int
1164wtmp_islogin(struct logininfo *li, struct utmp *ut)
1165{
Kevin Stevesef4eea92001-02-05 12:42:17 +00001166 if (strncmp(li->username, ut->ut_name,
Damien Miller8899ed32004-09-12 15:18:55 +10001167 MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001168# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001169 if (ut->ut_type & USER_PROCESS)
Damien Miller8899ed32004-09-12 15:18:55 +10001170 return (1);
Damien Millerdd47aa22000-06-27 11:18:27 +10001171# else
Damien Miller8899ed32004-09-12 15:18:55 +10001172 return (1);
Damien Millerdd47aa22000-06-27 11:18:27 +10001173# endif
andre6bb92372000-06-19 08:20:03 +00001174 }
Damien Miller8899ed32004-09-12 15:18:55 +10001175 return (0);
andre6bb92372000-06-19 08:20:03 +00001176}
1177
andre2ff7b5d2000-06-03 14:57:40 +00001178int
andre61e67252000-06-04 17:07:49 +00001179wtmp_get_entry(struct logininfo *li)
1180{
andre2ff7b5d2000-06-03 14:57:40 +00001181 struct stat st;
1182 struct utmp ut;
Damien Miller8899ed32004-09-12 15:18:55 +10001183 int fd, found = 0;
andre6bb92372000-06-19 08:20:03 +00001184
1185 /* Clear the time entries in our logininfo */
1186 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001187
1188 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001189 logit("%s: problem opening %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001190 WTMP_FILE, strerror(errno));
Damien Miller8899ed32004-09-12 15:18:55 +10001191 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001192 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001193 if (fstat(fd, &st) != 0) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001194 logit("%s: couldn't stat %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001195 WTMP_FILE, strerror(errno));
1196 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001197 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001198 }
andre2ff7b5d2000-06-03 14:57:40 +00001199
andre6bb92372000-06-19 08:20:03 +00001200 /* Seek to the start of the last struct utmp */
Kevin Steves52172652001-10-02 00:29:00 +00001201 if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
andre6bb92372000-06-19 08:20:03 +00001202 /* Looks like we've got a fresh wtmp file */
1203 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001204 return (0);
andre6bb92372000-06-19 08:20:03 +00001205 }
1206
1207 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001208 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001209 logit("%s: read of %s failed: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001210 WTMP_FILE, strerror(errno));
1211 close (fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001212 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001213 }
Damien Miller4a06f922011-01-02 21:43:59 +11001214 if (wtmp_islogin(li, &ut) ) {
andre6bb92372000-06-19 08:20:03 +00001215 found = 1;
Damien Miller8899ed32004-09-12 15:18:55 +10001216 /*
1217 * We've already checked for a time in struct
1218 * utmp, in login_getlast()
1219 */
Damien Millerdd47aa22000-06-27 11:18:27 +10001220# ifdef HAVE_TIME_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +00001221 li->tv_sec = ut.ut_time;
Damien Millerdd47aa22000-06-27 11:18:27 +10001222# else
andre2ff7b5d2000-06-03 14:57:40 +00001223# if HAVE_TV_IN_UTMP
1224 li->tv_sec = ut.ut_tv.tv_sec;
1225# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001226# endif
andre6bb92372000-06-19 08:20:03 +00001227 line_fullname(li->line, ut.ut_line,
Damien Miller8899ed32004-09-12 15:18:55 +10001228 MIN_SIZEOF(li->line, ut.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001229# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001230 strlcpy(li->hostname, ut.ut_host,
Damien Miller8899ed32004-09-12 15:18:55 +10001231 MIN_SIZEOF(li->hostname, ut.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001232# endif
andre6bb92372000-06-19 08:20:03 +00001233 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001234 }
andre6bb92372000-06-19 08:20:03 +00001235 /* Seek back 2 x struct utmp */
Kevin Steves52172652001-10-02 00:29:00 +00001236 if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
andre6bb92372000-06-19 08:20:03 +00001237 /* We've found the start of the file, so quit */
Damien Miller8899ed32004-09-12 15:18:55 +10001238 close(fd);
1239 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001240 }
andre6bb92372000-06-19 08:20:03 +00001241 }
1242
1243 /* We found an entry. Tidy up and return */
1244 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001245 return (1);
andre61e67252000-06-04 17:07:49 +00001246}
Damien Millerdd47aa22000-06-27 11:18:27 +10001247# endif /* USE_WTMP */
andre2ff7b5d2000-06-03 14:57:40 +00001248
1249
1250/**
andre61e67252000-06-04 17:07:49 +00001251 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +00001252 **/
1253
1254#ifdef USE_WTMPX
Damien Miller8899ed32004-09-12 15:18:55 +10001255/*
1256 * Write a wtmpx entry direct to the end of the file
1257 * This is a slight modification of code in OpenBSD's logwtmp.c
1258 */
andre2ff7b5d2000-06-03 14:57:40 +00001259static int
andre61e67252000-06-04 17:07:49 +00001260wtmpx_write(struct logininfo *li, struct utmpx *utx)
1261{
Darren Tuckerc28b88a2004-02-10 16:49:35 +11001262#ifndef HAVE_UPDWTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001263 struct stat buf;
1264 int fd, ret = 1;
1265
1266 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001267 logit("%s: problem opening %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001268 WTMPX_FILE, strerror(errno));
Damien Miller8899ed32004-09-12 15:18:55 +10001269 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001270 }
1271
Kevin Stevesef4eea92001-02-05 12:42:17 +00001272 if (fstat(fd, &buf) == 0)
Darren Tucker8661b562003-07-06 15:20:46 +10001273 if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
andre2ff7b5d2000-06-03 14:57:40 +00001274 ftruncate(fd, buf.st_size);
Damien Miller6b0279c2004-09-12 15:25:17 +10001275 logit("%s: problem writing %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001276 WTMPX_FILE, strerror(errno));
1277 ret = 0;
1278 }
Damien Miller8899ed32004-09-12 15:18:55 +10001279 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001280
Damien Miller8899ed32004-09-12 15:18:55 +10001281 return (ret);
Darren Tuckerc28b88a2004-02-10 16:49:35 +11001282#else
1283 updwtmpx(WTMPX_FILE, utx);
Damien Miller8899ed32004-09-12 15:18:55 +10001284 return (1);
Darren Tuckerc28b88a2004-02-10 16:49:35 +11001285#endif
andre61e67252000-06-04 17:07:49 +00001286}
andre2ff7b5d2000-06-03 14:57:40 +00001287
1288
1289static int
andre61e67252000-06-04 17:07:49 +00001290wtmpx_perform_login(struct logininfo *li)
1291{
andre2ff7b5d2000-06-03 14:57:40 +00001292 struct utmpx utx;
1293
1294 construct_utmpx(li, &utx);
Damien Miller8899ed32004-09-12 15:18:55 +10001295 return (wtmpx_write(li, &utx));
andre61e67252000-06-04 17:07:49 +00001296}
andre2ff7b5d2000-06-03 14:57:40 +00001297
1298
1299static int
andre61e67252000-06-04 17:07:49 +00001300wtmpx_perform_logout(struct logininfo *li)
1301{
andre2ff7b5d2000-06-03 14:57:40 +00001302 struct utmpx utx;
1303
1304 construct_utmpx(li, &utx);
Damien Miller8899ed32004-09-12 15:18:55 +10001305 return (wtmpx_write(li, &utx));
andre61e67252000-06-04 17:07:49 +00001306}
andre2ff7b5d2000-06-03 14:57:40 +00001307
1308
1309int
andre61e67252000-06-04 17:07:49 +00001310wtmpx_write_entry(struct logininfo *li)
1311{
andre2ff7b5d2000-06-03 14:57:40 +00001312 switch(li->type) {
1313 case LTYPE_LOGIN:
Damien Miller8899ed32004-09-12 15:18:55 +10001314 return (wtmpx_perform_login(li));
andre2ff7b5d2000-06-03 14:57:40 +00001315 case LTYPE_LOGOUT:
Damien Miller8899ed32004-09-12 15:18:55 +10001316 return (wtmpx_perform_logout(li));
andre2ff7b5d2000-06-03 14:57:40 +00001317 default:
Damien Miller6b0279c2004-09-12 15:25:17 +10001318 logit("%s: invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001319 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001320 }
andre61e67252000-06-04 17:07:49 +00001321}
andre2ff7b5d2000-06-03 14:57:40 +00001322
andre6bb92372000-06-19 08:20:03 +00001323/* Please see the notes above wtmp_islogin() for information about the
1324 next two functions */
1325
1326/* Return true if this wtmpx entry indicates a login */
1327static int
1328wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1329{
Darren Tucker0b8a2262010-01-09 18:18:04 +11001330 if (strncmp(li->username, utx->ut_user,
1331 MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001332# ifdef HAVE_TYPE_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001333 if (utx->ut_type == USER_PROCESS)
Damien Miller8899ed32004-09-12 15:18:55 +10001334 return (1);
Damien Millerdd47aa22000-06-27 11:18:27 +10001335# else
Damien Miller8899ed32004-09-12 15:18:55 +10001336 return (1);
Damien Millerdd47aa22000-06-27 11:18:27 +10001337# endif
andre6bb92372000-06-19 08:20:03 +00001338 }
Damien Miller8899ed32004-09-12 15:18:55 +10001339 return (0);
andre6bb92372000-06-19 08:20:03 +00001340}
1341
andre2ff7b5d2000-06-03 14:57:40 +00001342
1343int
andre61e67252000-06-04 17:07:49 +00001344wtmpx_get_entry(struct logininfo *li)
1345{
andre2ff7b5d2000-06-03 14:57:40 +00001346 struct stat st;
1347 struct utmpx utx;
andre6bb92372000-06-19 08:20:03 +00001348 int fd, found=0;
1349
1350 /* Clear the time entries */
1351 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001352
1353 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001354 logit("%s: problem opening %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001355 WTMPX_FILE, strerror(errno));
Damien Miller8899ed32004-09-12 15:18:55 +10001356 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001357 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001358 if (fstat(fd, &st) != 0) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001359 logit("%s: couldn't stat %s: %s", __func__,
Tim Ricecdb82942002-07-14 15:33:20 -07001360 WTMPX_FILE, strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +00001361 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001362 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001363 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001364
andre6bb92372000-06-19 08:20:03 +00001365 /* Seek to the start of the last struct utmpx */
Kevin Steves52172652001-10-02 00:29:00 +00001366 if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
andre6bb92372000-06-19 08:20:03 +00001367 /* probably a newly rotated wtmpx file */
1368 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001369 return (0);
andre6bb92372000-06-19 08:20:03 +00001370 }
andre2ff7b5d2000-06-03 14:57:40 +00001371
andre6bb92372000-06-19 08:20:03 +00001372 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001373 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
Damien Miller94cf4c82005-07-17 17:04:47 +10001374 logit("%s: read of %s failed: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001375 WTMPX_FILE, strerror(errno));
1376 close (fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001377 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001378 }
Damien Miller8899ed32004-09-12 15:18:55 +10001379 /*
Damien Miller94cf4c82005-07-17 17:04:47 +10001380 * Logouts are recorded as a blank username on a particular
Damien Miller8899ed32004-09-12 15:18:55 +10001381 * line. So, we just need to find the username in struct utmpx
1382 */
1383 if (wtmpx_islogin(li, &utx)) {
Tim Rice370e0ba2002-07-14 15:50:51 -07001384 found = 1;
Damien Miller8899ed32004-09-12 15:18:55 +10001385# if defined(HAVE_TV_IN_UTMPX)
andre2ff7b5d2000-06-03 14:57:40 +00001386 li->tv_sec = utx.ut_tv.tv_sec;
Damien Miller8899ed32004-09-12 15:18:55 +10001387# elif defined(HAVE_TIME_IN_UTMPX)
andre2ff7b5d2000-06-03 14:57:40 +00001388 li->tv_sec = utx.ut_time;
Damien Millerdd47aa22000-06-27 11:18:27 +10001389# endif
Damien Miller1a132252000-06-13 21:23:17 +10001390 line_fullname(li->line, utx.ut_line, sizeof(li->line));
Damien Miller8899ed32004-09-12 15:18:55 +10001391# if defined(HAVE_HOST_IN_UTMPX)
andre6bb92372000-06-19 08:20:03 +00001392 strlcpy(li->hostname, utx.ut_host,
Damien Miller8899ed32004-09-12 15:18:55 +10001393 MIN_SIZEOF(li->hostname, utx.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001394# endif
andre6bb92372000-06-19 08:20:03 +00001395 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001396 }
Kevin Steves52172652001-10-02 00:29:00 +00001397 if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
Damien Miller8899ed32004-09-12 15:18:55 +10001398 close(fd);
1399 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001400 }
andre6bb92372000-06-19 08:20:03 +00001401 }
1402
1403 close(fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001404 return (1);
andre61e67252000-06-04 17:07:49 +00001405}
Damien Millerd5bf3072000-06-07 21:32:13 +10001406#endif /* USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001407
andre2ff7b5d2000-06-03 14:57:40 +00001408/**
andre61e67252000-06-04 17:07:49 +00001409 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001410 **/
1411
1412#ifdef USE_LOGIN
andre2ff7b5d2000-06-03 14:57:40 +00001413static int
andre61e67252000-06-04 17:07:49 +00001414syslogin_perform_login(struct logininfo *li)
1415{
andre2ff7b5d2000-06-03 14:57:40 +00001416 struct utmp *ut;
1417
Damien Millerb0aae332004-09-12 15:26:00 +10001418 ut = xmalloc(sizeof(*ut));
andre2ff7b5d2000-06-03 14:57:40 +00001419 construct_utmp(li, ut);
1420 login(ut);
Damien Millerf211efc2003-03-10 11:23:06 +11001421 free(ut);
andre2ff7b5d2000-06-03 14:57:40 +00001422
Damien Miller8899ed32004-09-12 15:18:55 +10001423 return (1);
andre61e67252000-06-04 17:07:49 +00001424}
1425
andre2ff7b5d2000-06-03 14:57:40 +00001426static int
andre61e67252000-06-04 17:07:49 +00001427syslogin_perform_logout(struct logininfo *li)
1428{
Damien Millerdd47aa22000-06-27 11:18:27 +10001429# ifdef HAVE_LOGOUT
Darren Tucker4d2f3612004-04-08 10:57:05 +10001430 char line[UT_LINESIZE];
Kevin Stevesef4eea92001-02-05 12:42:17 +00001431
andre2ff7b5d2000-06-03 14:57:40 +00001432 (void)line_stripname(line, li->line, sizeof(line));
1433
Damien Miller8899ed32004-09-12 15:18:55 +10001434 if (!logout(line))
Damien Miller6b0279c2004-09-12 15:25:17 +10001435 logit("%s: logout() returned an error", __func__);
Damien Millerdd47aa22000-06-27 11:18:27 +10001436# ifdef HAVE_LOGWTMP
Damien Miller8899ed32004-09-12 15:18:55 +10001437 else
andre2ff7b5d2000-06-03 14:57:40 +00001438 logwtmp(line, "", "");
Damien Millerdd47aa22000-06-27 11:18:27 +10001439# endif
andre6bb92372000-06-19 08:20:03 +00001440 /* FIXME: (ATL - if the need arises) What to do if we have
1441 * login, but no logout? what if logout but no logwtmp? All
1442 * routines are in libutil so they should all be there,
1443 * but... */
Damien Millerdd47aa22000-06-27 11:18:27 +10001444# endif
Damien Miller8899ed32004-09-12 15:18:55 +10001445 return (1);
andre61e67252000-06-04 17:07:49 +00001446}
andre2ff7b5d2000-06-03 14:57:40 +00001447
andre2ff7b5d2000-06-03 14:57:40 +00001448int
andre61e67252000-06-04 17:07:49 +00001449syslogin_write_entry(struct logininfo *li)
1450{
andre2ff7b5d2000-06-03 14:57:40 +00001451 switch (li->type) {
1452 case LTYPE_LOGIN:
Damien Miller8899ed32004-09-12 15:18:55 +10001453 return (syslogin_perform_login(li));
andre2ff7b5d2000-06-03 14:57:40 +00001454 case LTYPE_LOGOUT:
Damien Miller8899ed32004-09-12 15:18:55 +10001455 return (syslogin_perform_logout(li));
andre2ff7b5d2000-06-03 14:57:40 +00001456 default:
Damien Miller6b0279c2004-09-12 15:25:17 +10001457 logit("%s: Invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001458 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001459 }
andre61e67252000-06-04 17:07:49 +00001460}
Damien Millerd5bf3072000-06-07 21:32:13 +10001461#endif /* USE_LOGIN */
andre2ff7b5d2000-06-03 14:57:40 +00001462
1463/* end of file log-syslogin.c */
1464
andre2ff7b5d2000-06-03 14:57:40 +00001465/**
andre61e67252000-06-04 17:07:49 +00001466 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001467 **/
1468
1469#ifdef USE_LASTLOG
1470
Damien Miller20e231f2009-02-12 13:12:21 +11001471#if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME)
1472/* open the file (using filemode) and seek to the login entry */
andre2ff7b5d2000-06-03 14:57:40 +00001473static int
Damien Miller20e231f2009-02-12 13:12:21 +11001474lastlog_openseek(struct logininfo *li, int *fd, int filemode)
andre61e67252000-06-04 17:07:49 +00001475{
Damien Miller20e231f2009-02-12 13:12:21 +11001476 off_t offset;
1477 char lastlog_file[1024];
andre2ff7b5d2000-06-03 14:57:40 +00001478 struct stat st;
1479
Damien Millerdd47aa22000-06-27 11:18:27 +10001480 if (stat(LASTLOG_FILE, &st) != 0) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001481 logit("%s: Couldn't stat %s: %s", __func__,
Damien Miller8899ed32004-09-12 15:18:55 +10001482 LASTLOG_FILE, strerror(errno));
1483 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001484 }
Damien Miller20e231f2009-02-12 13:12:21 +11001485 if (S_ISDIR(st.st_mode)) {
Damien Miller8899ed32004-09-12 15:18:55 +10001486 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1487 LASTLOG_FILE, li->username);
Damien Miller20e231f2009-02-12 13:12:21 +11001488 } else if (S_ISREG(st.st_mode)) {
1489 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1490 } else {
Damien Miller6b0279c2004-09-12 15:25:17 +10001491 logit("%s: %.100s is not a file or directory!", __func__,
Damien Miller8899ed32004-09-12 15:18:55 +10001492 LASTLOG_FILE);
1493 return (0);
Damien Millerdd47aa22000-06-27 11:18:27 +10001494 }
andre2ff7b5d2000-06-03 14:57:40 +00001495
Damien Miller405dc602003-04-09 21:12:52 +10001496 *fd = open(lastlog_file, filemode, 0600);
Damien Miller8899ed32004-09-12 15:18:55 +10001497 if (*fd < 0) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001498 debug("%s: Couldn't open %s: %s", __func__,
andre2ff7b5d2000-06-03 14:57:40 +00001499 lastlog_file, strerror(errno));
Damien Miller8899ed32004-09-12 15:18:55 +10001500 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001501 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001502
Damien Miller20e231f2009-02-12 13:12:21 +11001503 if (S_ISREG(st.st_mode)) {
Damien Millere477ef62000-08-15 10:21:17 +10001504 /* find this uid's offset in the lastlog file */
Damien Miller34ee4202010-11-05 10:52:37 +11001505 offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));
andre2ff7b5d2000-06-03 14:57:40 +00001506
Damien Miller8899ed32004-09-12 15:18:55 +10001507 if (lseek(*fd, offset, SEEK_SET) != offset) {
Damien Miller6b0279c2004-09-12 15:25:17 +10001508 logit("%s: %s->lseek(): %s", __func__,
1509 lastlog_file, strerror(errno));
Damien Miller4a06f922011-01-02 21:43:59 +11001510 close(*fd);
Damien Miller8899ed32004-09-12 15:18:55 +10001511 return (0);
Damien Millere477ef62000-08-15 10:21:17 +10001512 }
andre2ff7b5d2000-06-03 14:57:40 +00001513 }
Kevin Stevesef4eea92001-02-05 12:42:17 +00001514
Damien Miller8899ed32004-09-12 15:18:55 +10001515 return (1);
andre61e67252000-06-04 17:07:49 +00001516}
Damien Miller20e231f2009-02-12 13:12:21 +11001517#endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */
andre2ff7b5d2000-06-03 14:57:40 +00001518
Damien Miller20e231f2009-02-12 13:12:21 +11001519#ifdef LASTLOG_WRITE_PUTUTXLINE
andre2ff7b5d2000-06-03 14:57:40 +00001520int
andre61e67252000-06-04 17:07:49 +00001521lastlog_write_entry(struct logininfo *li)
1522{
andre2ff7b5d2000-06-03 14:57:40 +00001523 switch(li->type) {
1524 case LTYPE_LOGIN:
Damien Miller20e231f2009-02-12 13:12:21 +11001525 return 1; /* lastlog written by pututxline */
1526 default:
1527 logit("lastlog_write_entry: Invalid type field");
1528 return 0;
1529 }
1530}
1531#else /* LASTLOG_WRITE_PUTUTXLINE */
1532int
1533lastlog_write_entry(struct logininfo *li)
1534{
1535 struct lastlog last;
1536 int fd;
1537
1538 switch(li->type) {
1539 case LTYPE_LOGIN:
1540 /* create our struct lastlog */
1541 memset(&last, '\0', sizeof(last));
1542 line_stripname(last.ll_line, li->line, sizeof(last.ll_line));
1543 strlcpy(last.ll_host, li->hostname,
1544 MIN_SIZEOF(last.ll_host, li->hostname));
1545 last.ll_time = li->tv_sec;
1546
1547 if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
1548 return (0);
1549
1550 /* write the entry */
1551 if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
1552 close(fd);
1553 logit("%s: Error writing to %s: %s", __func__,
1554 LASTLOG_FILE, strerror(errno));
1555 return (0);
1556 }
1557
1558 close(fd);
1559 return (1);
andre2ff7b5d2000-06-03 14:57:40 +00001560 default:
Damien Miller6b0279c2004-09-12 15:25:17 +10001561 logit("%s: Invalid type field", __func__);
Damien Miller8899ed32004-09-12 15:18:55 +10001562 return (0);
andre2ff7b5d2000-06-03 14:57:40 +00001563 }
andre61e67252000-06-04 17:07:49 +00001564}
Damien Miller20e231f2009-02-12 13:12:21 +11001565#endif /* LASTLOG_WRITE_PUTUTXLINE */
andre2ff7b5d2000-06-03 14:57:40 +00001566
Damien Miller20e231f2009-02-12 13:12:21 +11001567#ifdef HAVE_GETLASTLOGXBYNAME
1568int
1569lastlog_get_entry(struct logininfo *li)
andre61e67252000-06-04 17:07:49 +00001570{
Damien Miller20e231f2009-02-12 13:12:21 +11001571 struct lastlogx l, *ll;
andre2ff7b5d2000-06-03 14:57:40 +00001572
Damien Miller20e231f2009-02-12 13:12:21 +11001573 if ((ll = getlastlogxbyname(li->username, &l)) == NULL) {
1574 memset(&l, '\0', sizeof(l));
1575 ll = &l;
1576 }
1577 line_fullname(li->line, ll->ll_line, sizeof(li->line));
1578 strlcpy(li->hostname, ll->ll_host,
1579 MIN_SIZEOF(li->hostname, ll->ll_host));
1580 li->tv_sec = ll->ll_tv.tv_sec;
1581 li->tv_usec = ll->ll_tv.tv_usec;
1582 return (1);
1583}
1584#else /* HAVE_GETLASTLOGXBYNAME */
andre2ff7b5d2000-06-03 14:57:40 +00001585int
andre61e67252000-06-04 17:07:49 +00001586lastlog_get_entry(struct logininfo *li)
1587{
andre2ff7b5d2000-06-03 14:57:40 +00001588 struct lastlog last;
Damien Miller7df881d2003-01-07 16:46:58 +11001589 int fd, ret;
andre2ff7b5d2000-06-03 14:57:40 +00001590
Damien Miller3a8a5cd2001-10-22 16:49:22 +10001591 if (!lastlog_openseek(li, &fd, O_RDONLY))
Damien Miller7df881d2003-01-07 16:46:58 +11001592 return (0);
Damien Miller3a8a5cd2001-10-22 16:49:22 +10001593
Damien Miller7df881d2003-01-07 16:46:58 +11001594 ret = atomicio(read, fd, &last, sizeof(last));
Damien Miller3a8a5cd2001-10-22 16:49:22 +10001595 close(fd);
1596
Damien Miller7df881d2003-01-07 16:46:58 +11001597 switch (ret) {
1598 case 0:
1599 memset(&last, '\0', sizeof(last));
1600 /* FALLTHRU */
1601 case sizeof(last):
Damien Miller20e231f2009-02-12 13:12:21 +11001602 line_fullname(li->line, last.ll_line, sizeof(li->line));
1603 strlcpy(li->hostname, last.ll_host,
1604 MIN_SIZEOF(li->hostname, last.ll_host));
1605 li->tv_sec = last.ll_time;
Damien Miller7df881d2003-01-07 16:46:58 +11001606 return (1);
1607 case -1:
Damien Millera8e06ce2003-11-21 23:48:55 +11001608 error("%s: Error reading from %s: %s", __func__,
Damien Miller7df881d2003-01-07 16:46:58 +11001609 LASTLOG_FILE, strerror(errno));
1610 return (0);
1611 default:
1612 error("%s: Error reading from %s: Expecting %d, got %d",
Darren Tuckerefc17472005-11-22 19:55:13 +11001613 __func__, LASTLOG_FILE, (int)sizeof(last), ret);
Damien Miller7df881d2003-01-07 16:46:58 +11001614 return (0);
1615 }
Damien Miller3a8a5cd2001-10-22 16:49:22 +10001616
Damien Miller7df881d2003-01-07 16:46:58 +11001617 /* NOTREACHED */
1618 return (0);
andre61e67252000-06-04 17:07:49 +00001619}
Damien Miller20e231f2009-02-12 13:12:21 +11001620#endif /* HAVE_GETLASTLOGXBYNAME */
Damien Millerd5bf3072000-06-07 21:32:13 +10001621#endif /* USE_LASTLOG */
Darren Tucker2fba9932005-02-02 23:30:24 +11001622
Darren Tucker261d93a2010-04-09 18:13:27 +10001623#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
1624 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
1625int
1626utmpx_get_entry(struct logininfo *li)
1627{
1628 struct utmpx *utx;
1629
1630 if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
1631 return (0);
1632 utx = getutxuser(li->username);
1633 if (utx == NULL) {
1634 endutxent();
1635 return (0);
1636 }
1637
1638 line_fullname(li->line, utx->ut_line,
1639 MIN_SIZEOF(li->line, utx->ut_line));
1640 strlcpy(li->hostname, utx->ut_host,
1641 MIN_SIZEOF(li->hostname, utx->ut_host));
1642 li->tv_sec = utx->ut_tv.tv_sec;
1643 li->tv_usec = utx->ut_tv.tv_usec;
1644 endutxent();
1645 return (1);
1646}
1647#endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */
1648
Darren Tucker2fba9932005-02-02 23:30:24 +11001649#ifdef USE_BTMP
1650 /*
1651 * Logs failed login attempts in _PATH_BTMP if that exists.
1652 * The most common login failure is to give password instead of username.
1653 * So the _PATH_BTMP file checked for the correct permission, so that
1654 * only root can read it.
1655 */
1656
1657void
1658record_failed_login(const char *username, const char *hostname,
1659 const char *ttyn)
1660{
1661 int fd;
1662 struct utmp ut;
1663 struct sockaddr_storage from;
Darren Tuckerefc17472005-11-22 19:55:13 +11001664 socklen_t fromlen = sizeof(from);
Darren Tucker2fba9932005-02-02 23:30:24 +11001665 struct sockaddr_in *a4;
1666 struct sockaddr_in6 *a6;
1667 time_t t;
1668 struct stat fst;
1669
1670 if (geteuid() != 0)
1671 return;
1672 if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) {
1673 debug("Unable to open the btmp file %s: %s", _PATH_BTMP,
1674 strerror(errno));
1675 return;
1676 }
1677 if (fstat(fd, &fst) < 0) {
1678 logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP,
1679 strerror(errno));
1680 goto out;
1681 }
Damien Miller88e341e2010-11-24 10:36:15 +11001682 if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){
Darren Tucker2fba9932005-02-02 23:30:24 +11001683 logit("Excess permission or bad ownership on file %s",
1684 _PATH_BTMP);
1685 goto out;
1686 }
1687
1688 memset(&ut, 0, sizeof(ut));
1689 /* strncpy because we don't necessarily want nul termination */
1690 strncpy(ut.ut_user, username, sizeof(ut.ut_user));
1691 strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line));
1692
1693 time(&t);
1694 ut.ut_time = t; /* ut_time is not always a time_t */
1695 ut.ut_type = LOGIN_PROCESS;
1696 ut.ut_pid = getpid();
1697
1698 /* strncpy because we don't necessarily want nul termination */
1699 strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
1700
1701 if (packet_connection_is_on_socket() &&
1702 getpeername(packet_get_connection_in(),
1703 (struct sockaddr *)&from, &fromlen) == 0) {
1704 ipv64_normalise_mapped(&from, &fromlen);
1705 if (from.ss_family == AF_INET) {
1706 a4 = (struct sockaddr_in *)&from;
1707 memcpy(&ut.ut_addr, &(a4->sin_addr),
1708 MIN_SIZEOF(ut.ut_addr, a4->sin_addr));
1709 }
1710#ifdef HAVE_ADDR_V6_IN_UTMP
1711 if (from.ss_family == AF_INET6) {
1712 a6 = (struct sockaddr_in6 *)&from;
1713 memcpy(&ut.ut_addr_v6, &(a6->sin6_addr),
1714 MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr));
1715 }
1716#endif
1717 }
1718
1719 if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut))
1720 error("Failed to write to %s: %s", _PATH_BTMP,
1721 strerror(errno));
1722
1723out:
1724 close(fd);
1725}
1726#endif /* USE_BTMP */