blob: 2c6330a0486cb42f6d3f169de78a3f9bd6b8a3e7 [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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Markus Friedl.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/**
34 ** loginrec.c: platform-independent login recording and lastlog retrieval
35 **/
36
andre61e67252000-06-04 17:07:49 +000037/*
38 The new login code explained
39 ============================
40
41 This code attempts to provide a common interface to login recording
42 (utmp and friends) and last login time retrieval.
43
44 Its primary means of achieving this is to use 'struct logininfo', a
45 union of all the useful fields in the various different types of
46 system login record structures one finds on UNIX variants.
47
48 We depend on autoconf to define which recording methods are to be
49 used, and which fields are contained in the relevant data structures
50 on the local system. Many C preprocessor symbols affect which code
51 gets compiled here.
52
53 The code is designed to make it easy to modify a particular
54 recording method, without affecting other methods nor requiring so
55 many nested conditional compilation blocks as were commonplace in
56 the old code.
57
58 For login recording, we try to use the local system's libraries as
59 these are clearly most likely to work correctly. For utmp systems
60 this usually means login() and logout() or setutent() etc., probably
61 in libutil, along with logwtmp() etc. On these systems, we fall back
62 to writing the files directly if we have to, though this method
63 requires very thorough testing so we do not corrupt local auditing
64 information. These files and their access methods are very system
65 specific indeed.
66
67 For utmpx systems, the corresponding library functions are
68 setutxent() etc. To the author's knowledge, all utmpx systems have
69 these library functions and so no direct write is attempted. If such
70 a system exists and needs support, direct analogues of the [uw]tmp
71 code should suffice.
72
73 Retrieving the time of last login ('lastlog') is in some ways even
74 more problemmatic than login recording. Some systems provide a
75 simple table of all users which we seek based on uid and retrieve a
76 relatively standard structure. Others record the same information in
77 a directory with a separate file, and others don't record the
78 information separately at all. For systems in the latter category,
79 we look backwards in the wtmp or wtmpx file for the last login entry
80 for our user. Naturally this is slower and on busy systems could
81 incur a significant performance penalty.
82
83 Calling the new code
84 --------------------
85
86 In OpenSSH all login recording and retrieval is performed in
87 login.c. Here you'll find working examples. Also, in the logintest.c
88 program there are more examples.
89
90 Internal handler calling method
91 -------------------------------
92
93 When a call is made to login_login() or login_logout(), both
94 routines set a struct logininfo flag defining which action (log in,
95 or log out) is to be taken. They both then call login_write(), which
96 calls whichever of the many structure-specific handlers autoconf
97 selects for the local system.
98
99 The handlers themselves handle system data structure specifics. Both
100 struct utmp and struct utmpx have utility functions (see
101 construct_utmp*()) to try to make it simpler to add extra systems
102 that introduce new features to either structure.
103
104 While it may seem terribly wasteful to replicate so much similar
105 code for each method, experience has shown that maintaining code to
106 write both struct utmp and utmpx in one function, whilst maintaining
107 support for all systems whether they have library support or not, is
108 a difficult and time-consuming task.
109
110 Lastlog support proceeds similarly. Functions login_get_lastlog()
111 (and its OpenSSH-tuned friend login_get_lastlog_time()) call
112 getlast_entry(), which tries one of three methods to find the last
113 login time. It uses local system lastlog support if it can,
114 otherwise it tries wtmp or wtmpx before giving up and returning 0,
115 meaning "tilt".
116
117 Maintenance
118 -----------
119
120 In many cases it's possible to tweak autoconf to select the correct
121 methods for a particular platform, either by improving the detection
122 code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
123 symbols for the platform.
124
125 Use logintest to check which symbols are defined before modifying
126 configure.in and loginrec.c. (You have to build logintest yourself
127 with 'make logintest' as it's not built by default.)
128
129 Otherwise, patches to the specific method(s) are very helpful!
130
131*/
132
andre2ff7b5d2000-06-03 14:57:40 +0000133/**
134 ** TODO:
andre61e67252000-06-04 17:07:49 +0000135 ** homegrown ttyslot()q
136 ** test, test, test
andre2ff7b5d2000-06-03 14:57:40 +0000137 **
138 ** Platform status:
139 ** ----------------
140 **
141 ** Known good:
142 ** Linux (Redhat 6.2, need more variants)
143 ** HP-UX 10.20 (gcc only)
andre6bb92372000-06-19 08:20:03 +0000144 ** IRIX
andre2ff7b5d2000-06-03 14:57:40 +0000145 **
146 ** Testing required: Please send reports!
147 ** Solaris
andre2ff7b5d2000-06-03 14:57:40 +0000148 ** NetBSD
149 ** HP-UX 11
andre60f3c982000-06-03 16:18:19 +0000150 ** AIX
andre2ff7b5d2000-06-03 14:57:40 +0000151 **
152 ** Platforms with known problems:
andre2ff7b5d2000-06-03 14:57:40 +0000153 ** NeXT
154 **
155 **/
156
157#include "includes.h"
158
andre2ff7b5d2000-06-03 14:57:40 +0000159#include "ssh.h"
160#include "xmalloc.h"
161#include "loginrec.h"
162
Damien Millerc1132e72000-08-18 14:08:38 +1000163RCSID("$Id: loginrec.c,v 1.21 2000/08/18 04:08:38 djm Exp $");
andre2ff7b5d2000-06-03 14:57:40 +0000164
165/**
166 ** prototypes for helper functions in this file
167 **/
168
169#if HAVE_UTMP_H
andre2ff7b5d2000-06-03 14:57:40 +0000170void set_utmp_time(struct logininfo *li, struct utmp *ut);
171void construct_utmp(struct logininfo *li, struct utmp *ut);
172#endif
173
174#ifdef HAVE_UTMPX_H
andre2ff7b5d2000-06-03 14:57:40 +0000175void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
176void construct_utmpx(struct logininfo *li, struct utmpx *ut);
177#endif
178
179int utmp_write_entry(struct logininfo *li);
180int utmpx_write_entry(struct logininfo *li);
181int wtmp_write_entry(struct logininfo *li);
182int wtmpx_write_entry(struct logininfo *li);
183int lastlog_write_entry(struct logininfo *li);
184int syslogin_write_entry(struct logininfo *li);
185
186int getlast_entry(struct logininfo *li);
187int lastlog_get_entry(struct logininfo *li);
188int wtmp_get_entry(struct logininfo *li);
189int wtmpx_get_entry(struct logininfo *li);
190
andre6bb92372000-06-19 08:20:03 +0000191/* pick the shortest string */
192#define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
193
andre2ff7b5d2000-06-03 14:57:40 +0000194/**
195 ** platform-independent login functions
196 **/
197
andre6bb92372000-06-19 08:20:03 +0000198/* login_login(struct logininfo *) -Record a login
199 *
200 * Call with a pointer to a struct logininfo initialised with
201 * login_init_entry() or login_alloc_entry()
202 *
203 * Returns:
204 * >0 if successful
205 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
206 */
andre61e67252000-06-04 17:07:49 +0000207int
208login_login (struct logininfo *li)
209{
210 li->type = LTYPE_LOGIN;
211 return login_write(li);
212}
213
214
andre6bb92372000-06-19 08:20:03 +0000215/* login_logout(struct logininfo *) - Record a logout
216 *
217 * Call as with login_login()
218 *
219 * Returns:
220 * >0 if successful
221 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
222 */
andre61e67252000-06-04 17:07:49 +0000223int
224login_logout(struct logininfo *li)
225{
226 li->type = LTYPE_LOGOUT;
227 return login_write(li);
228}
229
andre6bb92372000-06-19 08:20:03 +0000230/* login_get_lastlog_time(int) - Retrieve the last login time
231 *
232 * Retrieve the last login time for the given uid. Will try to use the
233 * system lastlog facilities if they are available, but will fall back
234 * to looking in wtmp/wtmpx if necessary
235 *
236 * Returns:
237 * 0 on failure, or if user has never logged in
238 * Time in seconds from the epoch if successful
239 *
240 * Useful preprocessor symbols:
241 * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
242 * info
243 * USE_LASTLOG: If set, indicates the presence of system lastlog
244 * facilities. If this and DISABLE_LASTLOG are not set,
245 * try to retrieve lastlog information from wtmp/wtmpx.
246 */
andre61e67252000-06-04 17:07:49 +0000247unsigned int
248login_get_lastlog_time(const int uid)
249{
250 struct logininfo li;
251
andre6bb92372000-06-19 08:20:03 +0000252 if (login_get_lastlog(&li, uid))
253 return li.tv_sec;
254 else
255 return 0;
andre61e67252000-06-04 17:07:49 +0000256}
257
andre6bb92372000-06-19 08:20:03 +0000258/* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
259 *
260 * Retrieve a logininfo structure populated (only partially) with
261 * information from the system lastlog data, or from wtmp/wtmpx if no
262 * system lastlog information exists.
263 *
264 * Note this routine must be given a pre-allocated logininfo.
265 *
266 * Returns:
267 * >0: A pointer to your struct logininfo if successful
268 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
269 *
270 */
andre61e67252000-06-04 17:07:49 +0000271struct logininfo *
272login_get_lastlog(struct logininfo *li, const int uid)
273{
andre6bb92372000-06-19 08:20:03 +0000274 struct passwd *pw;
andre6bb92372000-06-19 08:20:03 +0000275
Damien Miller348c9b72000-08-15 10:01:22 +1000276 memset(li, '\0', sizeof(*li));
andre61e67252000-06-04 17:07:49 +0000277 li->uid = uid;
andre6bb92372000-06-19 08:20:03 +0000278
Damien Miller53c5d462000-06-28 00:50:50 +1000279 /*
280 * If we don't have a 'real' lastlog, we need the username to
andre6bb92372000-06-19 08:20:03 +0000281 * reliably search wtmp(x) for the last login (see
Damien Miller53c5d462000-06-28 00:50:50 +1000282 * wtmp_get_entry().)
283 */
andre6bb92372000-06-19 08:20:03 +0000284 pw = getpwuid(uid);
Damien Millerdd47aa22000-06-27 11:18:27 +1000285 if (pw == NULL)
286 fatal("login_get_lastlog: Cannot find account for uid %i", uid);
287
andre98cabe02000-06-19 09:11:30 +0000288 /* No MIN_SIZEOF here - we absolutely *must not* truncate the
289 * username */
Damien Millerf8af08d2000-06-27 09:40:06 +1000290 strlcpy(li->username, pw->pw_name, sizeof(li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000291
andre61e67252000-06-04 17:07:49 +0000292 if (getlast_entry(li))
293 return li;
294 else
Damien Millerdd47aa22000-06-27 11:18:27 +1000295 return NULL;
andre61e67252000-06-04 17:07:49 +0000296}
297
298
andre6bb92372000-06-19 08:20:03 +0000299/* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise
300 * a logininfo structure
301 *
302 * This function creates a new struct logininfo, a data structure
303 * meant to carry the information required to portably record login info.
304 *
305 * Returns a pointer to a newly created struct logininfo. If memory
306 * allocation fails, the program halts.
307 */
andre61e67252000-06-04 17:07:49 +0000308struct
309logininfo *login_alloc_entry(int pid, const char *username,
310 const char *hostname, const char *line)
311{
andre2ff7b5d2000-06-03 14:57:40 +0000312 struct logininfo *newli;
313
Damien Miller348c9b72000-08-15 10:01:22 +1000314 newli = (struct logininfo *) xmalloc (sizeof(*newli));
andre61e67252000-06-04 17:07:49 +0000315 (void)login_init_entry(newli, pid, username, hostname, line);
316 return newli;
317}
andre2ff7b5d2000-06-03 14:57:40 +0000318
319
andre6bb92372000-06-19 08:20:03 +0000320/* login_free_entry(struct logininfo *) - free struct memory */
andre61e67252000-06-04 17:07:49 +0000321void
322login_free_entry(struct logininfo *li)
323{
324 xfree(li);
325}
326
andre2ff7b5d2000-06-03 14:57:40 +0000327
andre6bb92372000-06-19 08:20:03 +0000328/* login_init_entry(struct logininfo *, int, char*, char*, char*)
329 * - initialise a struct logininfo
330 *
331 * Populates a new struct logininfo, a data structure meant to carry
332 * the information required to portably record login info.
333 *
334 * Returns: 1
335 */
andre61e67252000-06-04 17:07:49 +0000336int
337login_init_entry(struct logininfo *li, int pid, const char *username,
338 const char *hostname, const char *line)
339{
Damien Millerf8af08d2000-06-27 09:40:06 +1000340 struct passwd *pw;
341
Damien Miller348c9b72000-08-15 10:01:22 +1000342 memset(li, 0, sizeof(*li));
andre2ff7b5d2000-06-03 14:57:40 +0000343
andre61e67252000-06-04 17:07:49 +0000344 li->pid = pid;
Damien Millerf8af08d2000-06-27 09:40:06 +1000345
andre2ff7b5d2000-06-03 14:57:40 +0000346 /* set the line information */
andre61e67252000-06-04 17:07:49 +0000347 if (line)
andre2ff7b5d2000-06-03 14:57:40 +0000348 line_fullname(li->line, line, sizeof(li->line));
andre2ff7b5d2000-06-03 14:57:40 +0000349
Damien Millerf8af08d2000-06-27 09:40:06 +1000350 if (username) {
andre2ff7b5d2000-06-03 14:57:40 +0000351 strlcpy(li->username, username, sizeof(li->username));
Damien Millerf8af08d2000-06-27 09:40:06 +1000352 pw = getpwnam(li->username);
353 if (pw == NULL)
354 fatal("login_init_entry: Cannot find user \"%s\"", li->username);
355 li->uid = pw->pw_uid;
356 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000357
andre61e67252000-06-04 17:07:49 +0000358 if (hostname)
andre2ff7b5d2000-06-03 14:57:40 +0000359 strlcpy(li->hostname, hostname, sizeof(li->hostname));
Damien Millerf8af08d2000-06-27 09:40:06 +1000360
andre61e67252000-06-04 17:07:49 +0000361 return 1;
andre2ff7b5d2000-06-03 14:57:40 +0000362}
363
andre6bb92372000-06-19 08:20:03 +0000364/* login_set_current_time(struct logininfo *) - set the current time
365 *
366 * Set the current time in a logininfo structure. This function is
367 * meant to eliminate the need to deal with system dependencies for
368 * time handling.
369 */
andre2ff7b5d2000-06-03 14:57:40 +0000370void
andre61e67252000-06-04 17:07:49 +0000371login_set_current_time(struct logininfo *li)
372{
andre2ff7b5d2000-06-03 14:57:40 +0000373 struct timeval tv;
374
375 gettimeofday(&tv, NULL);
Damien Millerf8af08d2000-06-27 09:40:06 +1000376
377 li->tv_sec = tv.tv_sec;
378 li->tv_usec = tv.tv_usec;
andre2ff7b5d2000-06-03 14:57:40 +0000379}
380
andre61e67252000-06-04 17:07:49 +0000381/* copy a sockaddr_* into our logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000382void
andre61e67252000-06-04 17:07:49 +0000383login_set_addr(struct logininfo *li, const struct sockaddr *sa,
384 const unsigned int sa_size)
385{
386 unsigned int bufsize = sa_size;
387
388 /* make sure we don't overrun our union */
389 if (sizeof(li->hostaddr) < sa_size)
390 bufsize = sizeof(li->hostaddr);
391
392 memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
andre2ff7b5d2000-06-03 14:57:40 +0000393}
394
andre2ff7b5d2000-06-03 14:57:40 +0000395
andre61e67252000-06-04 17:07:49 +0000396/**
397 ** login_write: Call low-level recording functions based on autoconf
398 ** results
399 **/
andre2ff7b5d2000-06-03 14:57:40 +0000400int
andre61e67252000-06-04 17:07:49 +0000401login_write (struct logininfo *li)
402{
andre2ff7b5d2000-06-03 14:57:40 +0000403 if ((int)geteuid() != 0) {
404 log("Attempt to write login records by non-root user (aborting)");
405 return 1;
406 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000407
andre2ff7b5d2000-06-03 14:57:40 +0000408 /* set the timestamp */
409 login_set_current_time(li);
410#ifdef USE_LOGIN
411 syslogin_write_entry(li);
412#endif
413#ifdef USE_LASTLOG
414 if (li->type == LTYPE_LOGIN) {
415 lastlog_write_entry(li);
416 }
417#endif
418#ifdef USE_UTMP
419 utmp_write_entry(li);
420#endif
421#ifdef USE_WTMP
422 wtmp_write_entry(li);
423#endif
424#ifdef USE_UTMPX
425 utmpx_write_entry(li);
426#endif
427#ifdef USE_WTMPX
428 wtmpx_write_entry(li);
429#endif
430 return 0;
431}
432
andre2ff7b5d2000-06-03 14:57:40 +0000433/**
andre61e67252000-06-04 17:07:49 +0000434 ** getlast_entry: Call low-level functions to retrieve the last login
435 ** time.
andre2ff7b5d2000-06-03 14:57:40 +0000436 **/
437
andre61e67252000-06-04 17:07:49 +0000438/* take the uid in li and return the last login time */
439int
440getlast_entry(struct logininfo *li)
441{
442#ifdef USE_LASTLOG
Damien Miller53c5d462000-06-28 00:50:50 +1000443 return(lastlog_get_entry(li));
Damien Millerdd47aa22000-06-27 11:18:27 +1000444#else /* !USE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000445
Damien Millerdd47aa22000-06-27 11:18:27 +1000446#ifdef DISABLE_LASTLOG
andreecaabf12000-06-12 22:21:44 +0000447 /* On some systems we shouldn't even try to obtain last login
448 * time, e.g. AIX */
449 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +1000450# else /* DISABLE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000451 /* Try to retrieve the last login time from wtmp */
Damien Millerdd47aa22000-06-27 11:18:27 +1000452# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
andre61e67252000-06-04 17:07:49 +0000453 /* retrieve last login time from utmp */
Damien Millerdd47aa22000-06-27 11:18:27 +1000454 return (wtmp_get_entry(li));
455# else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
andre61e67252000-06-04 17:07:49 +0000456 /* If wtmp isn't available, try wtmpx */
Damien Millerdd47aa22000-06-27 11:18:27 +1000457# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
andre61e67252000-06-04 17:07:49 +0000458 /* retrieve last login time from utmpx */
Damien Millerdd47aa22000-06-27 11:18:27 +1000459 return (wtmpx_get_entry(li));
460# else
andre61e67252000-06-04 17:07:49 +0000461 /* Give up: No means of retrieving last login time */
462 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +1000463# endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
464# endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
465# endif /* DISABLE_LASTLOG */
466#endif /* USE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000467}
468
469
470
andre2ff7b5d2000-06-03 14:57:40 +0000471/*
andre61e67252000-06-04 17:07:49 +0000472 * 'line' string utility functions
473 *
474 * These functions process the 'line' string into one of three forms:
475 *
andre2ff7b5d2000-06-03 14:57:40 +0000476 * 1. The full filename (including '/dev')
477 * 2. The stripped name (excluding '/dev')
andre61e67252000-06-04 17:07:49 +0000478 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
479 * /dev/pts/1 -> ts/1 )
andre2ff7b5d2000-06-03 14:57:40 +0000480 *
481 * Form 3 is used on some systems to identify a .tmp.? entry when
482 * attempting to remove it. Typically both addition and removal is
andre61e67252000-06-04 17:07:49 +0000483 * performed by one application - say, sshd - so as long as the choice
484 * uniquely identifies a terminal it's ok.
andre2ff7b5d2000-06-03 14:57:40 +0000485 */
486
487
andre61e67252000-06-04 17:07:49 +0000488/* line_fullname(): add the leading '/dev/' if it doesn't exist make
489 * sure dst has enough space, if not just copy src (ugh) */
andre2ff7b5d2000-06-03 14:57:40 +0000490char *
andre61e67252000-06-04 17:07:49 +0000491line_fullname(char *dst, const char *src, int dstsize)
492{
andre2ff7b5d2000-06-03 14:57:40 +0000493 memset(dst, '\0', dstsize);
494 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
495 strlcpy(dst, src, dstsize);
496 else {
Damien Miller1a132252000-06-13 21:23:17 +1000497 strlcpy(dst, "/dev/", dstsize);
andre2ff7b5d2000-06-03 14:57:40 +0000498 strlcat(dst, src, dstsize);
499 }
500 return dst;
501}
502
andre61e67252000-06-04 17:07:49 +0000503/* line_stripname(): strip the leading '/dev' if it exists, return dst */
andre2ff7b5d2000-06-03 14:57:40 +0000504char *
andre61e67252000-06-04 17:07:49 +0000505line_stripname(char *dst, const char *src, int dstsize)
506{
andre2ff7b5d2000-06-03 14:57:40 +0000507 memset(dst, '\0', dstsize);
508 if (strncmp(src, "/dev/", 5) == 0)
509 strlcpy(dst, &src[5], dstsize);
510 else
511 strlcpy(dst, src, dstsize);
512 return dst;
andre61e67252000-06-04 17:07:49 +0000513}
514
andre61e67252000-06-04 17:07:49 +0000515/* line_abbrevname(): Return the abbreviated (usually four-character)
516 * form of the line (Just use the last <dstsize> characters of the
517 * full name.)
518 *
519 * NOTE: use strncpy because we do NOT necessarily want zero
520 * termination */
andre2ff7b5d2000-06-03 14:57:40 +0000521char *
Damien Millerdd47aa22000-06-27 11:18:27 +1000522line_abbrevname(char *dst, const char *src, int dstsize)
523{
524 size_t len;
525
andre2ff7b5d2000-06-03 14:57:40 +0000526 memset(dst, '\0', dstsize);
Damien Millerdd47aa22000-06-27 11:18:27 +1000527
Damien Miller8e81ed32000-07-01 13:17:42 +1000528 /* Always skip prefix if present */
529 if (strncmp(src, "/dev/", 5) == 0)
530 src += 5;
531
Damien Millerdd47aa22000-06-27 11:18:27 +1000532 len = strlen(src);
533
Damien Miller8e81ed32000-07-01 13:17:42 +1000534 if (len > 0) {
535 if (((int)len - dstsize) > 0)
536 src += ((int)len - dstsize);
537
538 /* note: _don't_ change this to strlcpy */
539 strncpy(dst, src, (size_t)dstsize);
Damien Millerdd47aa22000-06-27 11:18:27 +1000540 }
541
andre2ff7b5d2000-06-03 14:57:40 +0000542 return dst;
543}
544
andre2ff7b5d2000-06-03 14:57:40 +0000545/**
546 ** utmp utility functions
andre61e67252000-06-04 17:07:49 +0000547 **
548 ** These functions manipulate struct utmp, taking system differences
549 ** into account.
andre2ff7b5d2000-06-03 14:57:40 +0000550 **/
551
552#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
553
andre2ff7b5d2000-06-03 14:57:40 +0000554/* build the utmp structure */
555void
andre61e67252000-06-04 17:07:49 +0000556set_utmp_time(struct logininfo *li, struct utmp *ut)
557{
Damien Millerdd47aa22000-06-27 11:18:27 +1000558# ifdef HAVE_TV_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000559 ut->ut_tv.tv_sec = li->tv_sec;
560 ut->ut_tv.tv_usec = li->tv_usec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000561# else
andre2ff7b5d2000-06-03 14:57:40 +0000562# ifdef HAVE_TIME_IN_UTMP
563 ut->ut_time = li->tv_sec;
564# endif
Damien Millerdd47aa22000-06-27 11:18:27 +1000565# endif
andre2ff7b5d2000-06-03 14:57:40 +0000566}
567
568void
569construct_utmp(struct logininfo *li,
andre61e67252000-06-04 17:07:49 +0000570 struct utmp *ut)
571{
Damien Miller348c9b72000-08-15 10:01:22 +1000572 memset(ut, '\0', sizeof(*ut));
andre6bb92372000-06-19 08:20:03 +0000573
574 /* First fill out fields used for both logins and logouts */
575
Damien Millerdd47aa22000-06-27 11:18:27 +1000576# ifdef HAVE_ID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000577 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000578# endif
andre2ff7b5d2000-06-03 14:57:40 +0000579
Damien Millerdd47aa22000-06-27 11:18:27 +1000580# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +0000581 /* This is done here to keep utmp constants out of struct logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000582 switch (li->type) {
583 case LTYPE_LOGIN:
584 ut->ut_type = USER_PROCESS;
585 break;
586 case LTYPE_LOGOUT:
587 ut->ut_type = DEAD_PROCESS;
588 break;
589 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000590# endif
andre6bb92372000-06-19 08:20:03 +0000591 set_utmp_time(li, ut);
andre2ff7b5d2000-06-03 14:57:40 +0000592
andre6bb92372000-06-19 08:20:03 +0000593 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000594
595# ifdef HAVE_PID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000596 ut->ut_pid = li->pid;
Damien Millerdd47aa22000-06-27 11:18:27 +1000597# endif
andre6bb92372000-06-19 08:20:03 +0000598
599 /* If we're logging out, leave all other fields blank */
600 if (li->type == LTYPE_LOGOUT)
601 return;
602
Damien Millerdd47aa22000-06-27 11:18:27 +1000603 /*
604 * These fields are only used when logging in, and are blank
605 * for logouts.
606 */
andre6bb92372000-06-19 08:20:03 +0000607
608 /* Use strncpy because we don't necessarily want null termination */
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000609 strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000610# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +0000611 strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000612# endif
613# ifdef HAVE_ADDR_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000614 /* this is just a 32-bit IP address */
615 if (li->hostaddr.sa.sa_family == AF_INET)
616 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
Damien Millerdd47aa22000-06-27 11:18:27 +1000617# endif
andre61e67252000-06-04 17:07:49 +0000618}
Damien Millerdd47aa22000-06-27 11:18:27 +1000619#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
andre61e67252000-06-04 17:07:49 +0000620
andre2ff7b5d2000-06-03 14:57:40 +0000621/**
622 ** utmpx utility functions
andre61e67252000-06-04 17:07:49 +0000623 **
624 ** These functions manipulate struct utmpx, accounting for system
625 ** variations.
andre2ff7b5d2000-06-03 14:57:40 +0000626 **/
627
628#if defined(USE_UTMPX) || defined (USE_WTMPX)
andre2ff7b5d2000-06-03 14:57:40 +0000629/* build the utmpx structure */
630void
andre61e67252000-06-04 17:07:49 +0000631set_utmpx_time(struct logininfo *li, struct utmpx *utx)
632{
Damien Millerdd47aa22000-06-27 11:18:27 +1000633# ifdef HAVE_TV_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000634 utx->ut_tv.tv_sec = li->tv_sec;
635 utx->ut_tv.tv_usec = li->tv_usec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000636# else /* HAVE_TV_IN_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000637# ifdef HAVE_TIME_IN_UTMPX
638 utx->ut_time = li->tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000639# endif /* HAVE_TIME_IN_UTMPX */
640# endif /* HAVE_TV_IN_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000641}
642
andre61e67252000-06-04 17:07:49 +0000643void
644construct_utmpx(struct logininfo *li, struct utmpx *utx)
645{
Damien Miller348c9b72000-08-15 10:01:22 +1000646 memset(utx, '\0', sizeof(*utx));
Damien Miller8e81ed32000-07-01 13:17:42 +1000647# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000648 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
Damien Miller8e81ed32000-07-01 13:17:42 +1000649# endif
andre2ff7b5d2000-06-03 14:57:40 +0000650
651 /* this is done here to keep utmp constants out of loginrec.h */
652 switch (li->type) {
653 case LTYPE_LOGIN:
654 utx->ut_type = USER_PROCESS;
655 break;
656 case LTYPE_LOGOUT:
657 utx->ut_type = DEAD_PROCESS;
658 break;
659 }
andre2ff7b5d2000-06-03 14:57:40 +0000660 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
andre2ff7b5d2000-06-03 14:57:40 +0000661 set_utmpx_time(li, utx);
andre6bb92372000-06-19 08:20:03 +0000662 utx->ut_pid = li->pid;
663
664 if (li->type == LTYPE_LOGOUT)
665 return;
666
Damien Millerdd47aa22000-06-27 11:18:27 +1000667 /*
668 * These fields are only used when logging in, and are blank
669 * for logouts.
670 */
andre6bb92372000-06-19 08:20:03 +0000671
672 /* strncpy(): Don't necessarily want null termination */
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000673 strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000674# ifdef HAVE_HOST_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +0000675 strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000676# endif
677# ifdef HAVE_ADDR_IN_UTMPX
andre61e67252000-06-04 17:07:49 +0000678 /* FIXME: (ATL) not supported yet */
Damien Millerdd47aa22000-06-27 11:18:27 +1000679# endif
680# ifdef HAVE_SYSLEN_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +0000681 /* ut_syslen is the length of the utx_host string */
682 utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +1000683# endif
andre61e67252000-06-04 17:07:49 +0000684}
Damien Millerdd47aa22000-06-27 11:18:27 +1000685#endif /* USE_UTMPX || USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000686
687/**
andre61e67252000-06-04 17:07:49 +0000688 ** Low-level utmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000689 **/
690
691/* FIXME: (ATL) utmp_write_direct needs testing */
andre2ff7b5d2000-06-03 14:57:40 +0000692#ifdef USE_UTMP
693
andre2ff7b5d2000-06-03 14:57:40 +0000694/* if we can, use pututline() etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000695# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
696 defined(HAVE_PUTUTLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000697# define UTMP_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000698# endif
andre2ff7b5d2000-06-03 14:57:40 +0000699
700
701/* write a utmp entry with the system's help (pututline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000702# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000703static int
andre61e67252000-06-04 17:07:49 +0000704utmp_write_library(struct logininfo *li, struct utmp *ut)
705{
andre2ff7b5d2000-06-03 14:57:40 +0000706 setutent();
707 pututline(ut);
708
Damien Millerdd47aa22000-06-27 11:18:27 +1000709# ifdef HAVE_ENDUTENT
andre2ff7b5d2000-06-03 14:57:40 +0000710 endutent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000711# endif
andre2ff7b5d2000-06-03 14:57:40 +0000712 return 1;
andre61e67252000-06-04 17:07:49 +0000713}
Damien Millerdd47aa22000-06-27 11:18:27 +1000714# else /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000715
716/* write a utmp entry direct to the file */
andre61e67252000-06-04 17:07:49 +0000717/* This is a slightly modification of code in OpenBSD's login.c */
andre2ff7b5d2000-06-03 14:57:40 +0000718static int
andre61e67252000-06-04 17:07:49 +0000719utmp_write_direct(struct logininfo *li, struct utmp *ut)
720{
andre2ff7b5d2000-06-03 14:57:40 +0000721 struct utmp old_ut;
722 register int fd;
723 int tty;
724
andre6bb92372000-06-19 08:20:03 +0000725 /* FIXME: (ATL) ttyslot() needs local implementation */
Damien Miller348c9b72000-08-15 10:01:22 +1000726
727#if defined(SUNOS4) && defined(HAVE_GETTTYENT)
728 register struct ttyent *ty;
729
730 tty=0;
731
732 setttyent();
733 while ((struct ttyent *)0 != (ty = getttyent())) {
734 tty++;
735 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
736 break;
737 }
738 endttyent();
739
740 if((struct ttyent *)0 == ty) {
741 log("utmp_write_entry: tty not found");
742 return(1);
743 }
744#else /* FIXME */
745
andre2ff7b5d2000-06-03 14:57:40 +0000746 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
747
Damien Miller348c9b72000-08-15 10:01:22 +1000748#endif /* SUNOS4 && HAVE_GETTTYENT */
749
andre2ff7b5d2000-06-03 14:57:40 +0000750 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
751 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
752 /*
753 * Prevent luser from zero'ing out ut_host.
754 * If the new ut_line is empty but the old one is not
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000755 * and ut_line and ut_name match, preserve the old ut_line.
andre2ff7b5d2000-06-03 14:57:40 +0000756 */
Damien Miller53c5d462000-06-28 00:50:50 +1000757 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
758 (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
759 (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000760 (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
andre2ff7b5d2000-06-03 14:57:40 +0000761 (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
Damien Miller53c5d462000-06-28 00:50:50 +1000762 }
763
andre2ff7b5d2000-06-03 14:57:40 +0000764 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
Damien Miller36ccb5c2000-08-09 16:34:27 +1000765 if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
andre2ff7b5d2000-06-03 14:57:40 +0000766 log("utmp_write_direct: error writing %s: %s",
andre6bb92372000-06-19 08:20:03 +0000767 UTMP_FILE, strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +0000768
769 (void)close(fd);
770 return 1;
Damien Miller53c5d462000-06-28 00:50:50 +1000771 } else {
andre2ff7b5d2000-06-03 14:57:40 +0000772 return 0;
Damien Miller53c5d462000-06-28 00:50:50 +1000773 }
andre61e67252000-06-04 17:07:49 +0000774}
Damien Millerdd47aa22000-06-27 11:18:27 +1000775# endif /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000776
777static int
andre61e67252000-06-04 17:07:49 +0000778utmp_perform_login(struct logininfo *li)
779{
andre2ff7b5d2000-06-03 14:57:40 +0000780 struct utmp ut;
781
782 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000783# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000784 if (!utmp_write_library(li, &ut)) {
andre6bb92372000-06-19 08:20:03 +0000785 log("utmp_perform_login: utmp_write_library() failed");
andre2ff7b5d2000-06-03 14:57:40 +0000786 return 0;
787 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000788# else
andre2ff7b5d2000-06-03 14:57:40 +0000789 if (!utmp_write_direct(li, &ut)) {
790 log("utmp_perform_login: utmp_write_direct() failed");
791 return 0;
792 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000793# endif
andre2ff7b5d2000-06-03 14:57:40 +0000794 return 1;
andre61e67252000-06-04 17:07:49 +0000795}
andre2ff7b5d2000-06-03 14:57:40 +0000796
797
798static int
andre61e67252000-06-04 17:07:49 +0000799utmp_perform_logout(struct logininfo *li)
800{
andre2ff7b5d2000-06-03 14:57:40 +0000801 struct utmp ut;
802
andre6bb92372000-06-19 08:20:03 +0000803 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000804# ifdef UTMP_USE_LIBRARY
andre6bb92372000-06-19 08:20:03 +0000805 if (!utmp_write_library(li, &ut)) {
806 log("utmp_perform_logout: utmp_write_library() failed");
807 return 0;
808 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000809# else
andre6bb92372000-06-19 08:20:03 +0000810 if (!utmp_write_direct(li, &ut)) {
811 log("utmp_perform_logout: utmp_write_direct() failed");
812 return 0;
813 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000814# endif
andre2ff7b5d2000-06-03 14:57:40 +0000815 return 1;
andre61e67252000-06-04 17:07:49 +0000816}
andre2ff7b5d2000-06-03 14:57:40 +0000817
818
819int
andre61e67252000-06-04 17:07:49 +0000820utmp_write_entry(struct logininfo *li)
821{
andre2ff7b5d2000-06-03 14:57:40 +0000822 switch(li->type) {
823 case LTYPE_LOGIN:
824 return utmp_perform_login(li);
825
826 case LTYPE_LOGOUT:
827 return utmp_perform_logout(li);
828
829 default:
830 log("utmp_write_entry: invalid type field");
831 return 0;
832 }
andre61e67252000-06-04 17:07:49 +0000833}
Damien Millerdd47aa22000-06-27 11:18:27 +1000834#endif /* USE_UTMP */
andre2ff7b5d2000-06-03 14:57:40 +0000835
836
837/**
andre61e67252000-06-04 17:07:49 +0000838 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000839 **/
840
841/* not much point if we don't want utmpx entries */
842#ifdef USE_UTMPX
843
andre2ff7b5d2000-06-03 14:57:40 +0000844/* if we have the wherewithall, use pututxline etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000845# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
846 defined(HAVE_PUTUTXLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000847# define UTMPX_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000848# endif
andre2ff7b5d2000-06-03 14:57:40 +0000849
850
851/* write a utmpx entry with the system's help (pututxline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000852# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000853static int
andre61e67252000-06-04 17:07:49 +0000854utmpx_write_library(struct logininfo *li, struct utmpx *utx)
855{
andre2ff7b5d2000-06-03 14:57:40 +0000856 setutxent();
857 pututxline(utx);
858
Damien Millerdd47aa22000-06-27 11:18:27 +1000859# ifdef HAVE_ENDUTXENT
andre2ff7b5d2000-06-03 14:57:40 +0000860 endutxent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000861# endif
andre2ff7b5d2000-06-03 14:57:40 +0000862 return 1;
andre61e67252000-06-04 17:07:49 +0000863}
andre2ff7b5d2000-06-03 14:57:40 +0000864
Damien Millerdd47aa22000-06-27 11:18:27 +1000865# else /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000866
867/* write a utmp entry direct to the file */
868static int
andre61e67252000-06-04 17:07:49 +0000869utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
870{
andre2ff7b5d2000-06-03 14:57:40 +0000871 log("utmpx_write_direct: not implemented!");
872 return 0;
andre61e67252000-06-04 17:07:49 +0000873}
Damien Millerdd47aa22000-06-27 11:18:27 +1000874# endif /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000875
876static int
andre61e67252000-06-04 17:07:49 +0000877utmpx_perform_login(struct logininfo *li)
878{
andre2ff7b5d2000-06-03 14:57:40 +0000879 struct utmpx utx;
880
881 construct_utmpx(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000882# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000883 if (!utmpx_write_library(li, &utx)) {
884 log("utmpx_perform_login: utmp_write_library() failed");
885 return 0;
886 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000887# else
andre2ff7b5d2000-06-03 14:57:40 +0000888 if (!utmpx_write_direct(li, &ut)) {
889 log("utmpx_perform_login: utmp_write_direct() failed");
890 return 0;
891 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000892# endif
andre2ff7b5d2000-06-03 14:57:40 +0000893 return 1;
andre61e67252000-06-04 17:07:49 +0000894}
andre2ff7b5d2000-06-03 14:57:40 +0000895
896
897static int
andre61e67252000-06-04 17:07:49 +0000898utmpx_perform_logout(struct logininfo *li)
899{
andre2ff7b5d2000-06-03 14:57:40 +0000900 struct utmpx utx;
901
902 memset(&utx, '\0', sizeof(utx));
903 set_utmpx_time(li, &utx);
904 line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000905# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000906 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000907# endif
908# ifdef HAVE_TYPE_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000909 utx.ut_type = DEAD_PROCESS;
Damien Millerdd47aa22000-06-27 11:18:27 +1000910# endif
andre2ff7b5d2000-06-03 14:57:40 +0000911
Damien Millerdd47aa22000-06-27 11:18:27 +1000912# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000913 utmpx_write_library(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000914# else
andre2ff7b5d2000-06-03 14:57:40 +0000915 utmpx_write_direct(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000916# endif
andre2ff7b5d2000-06-03 14:57:40 +0000917 return 1;
andre61e67252000-06-04 17:07:49 +0000918}
andre2ff7b5d2000-06-03 14:57:40 +0000919
andre2ff7b5d2000-06-03 14:57:40 +0000920int
andre61e67252000-06-04 17:07:49 +0000921utmpx_write_entry(struct logininfo *li)
922{
andre2ff7b5d2000-06-03 14:57:40 +0000923 switch(li->type) {
924 case LTYPE_LOGIN:
925 return utmpx_perform_login(li);
926 case LTYPE_LOGOUT:
927 return utmpx_perform_logout(li);
928 default:
929 log("utmpx_write_entry: invalid type field");
930 return 0;
931 }
andre61e67252000-06-04 17:07:49 +0000932}
Damien Millerdd47aa22000-06-27 11:18:27 +1000933#endif /* USE_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000934
935
936/**
andre61e67252000-06-04 17:07:49 +0000937 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000938 **/
939
940#ifdef USE_WTMP
941
andre2ff7b5d2000-06-03 14:57:40 +0000942/* write a wtmp entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000943/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000944static int
andre61e67252000-06-04 17:07:49 +0000945wtmp_write(struct logininfo *li, struct utmp *ut)
946{
andre2ff7b5d2000-06-03 14:57:40 +0000947 struct stat buf;
948 int fd, ret = 1;
949
950 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
951 log("wtmp_write: problem writing %s: %s",
952 WTMP_FILE, strerror(errno));
953 return 0;
954 }
andre61e67252000-06-04 17:07:49 +0000955 if (fstat(fd, &buf) == 0)
Damien Miller53c5d462000-06-28 00:50:50 +1000956 if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
andre2ff7b5d2000-06-03 14:57:40 +0000957 ftruncate(fd, buf.st_size);
958 log("wtmp_write: problem writing %s: %s",
959 WTMP_FILE, strerror(errno));
960 ret = 0;
961 }
962 (void)close(fd);
andre2ff7b5d2000-06-03 14:57:40 +0000963 return ret;
andre61e67252000-06-04 17:07:49 +0000964}
andre2ff7b5d2000-06-03 14:57:40 +0000965
andre2ff7b5d2000-06-03 14:57:40 +0000966static int
Damien Millerdd47aa22000-06-27 11:18:27 +1000967wtmp_perform_login(struct logininfo *li)
968{
andre2ff7b5d2000-06-03 14:57:40 +0000969 struct utmp ut;
970
971 construct_utmp(li, &ut);
972 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000973}
andre2ff7b5d2000-06-03 14:57:40 +0000974
975
976static int
andre61e67252000-06-04 17:07:49 +0000977wtmp_perform_logout(struct logininfo *li)
978{
andre2ff7b5d2000-06-03 14:57:40 +0000979 struct utmp ut;
980
981 construct_utmp(li, &ut);
andre2ff7b5d2000-06-03 14:57:40 +0000982 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000983}
andre2ff7b5d2000-06-03 14:57:40 +0000984
985
986int
andre61e67252000-06-04 17:07:49 +0000987wtmp_write_entry(struct logininfo *li)
988{
andre2ff7b5d2000-06-03 14:57:40 +0000989 switch(li->type) {
990 case LTYPE_LOGIN:
991 return wtmp_perform_login(li);
992 case LTYPE_LOGOUT:
993 return wtmp_perform_logout(li);
994 default:
995 log("wtmp_write_entry: invalid type field");
996 return 0;
997 }
andre61e67252000-06-04 17:07:49 +0000998}
andre2ff7b5d2000-06-03 14:57:40 +0000999
1000
andre6bb92372000-06-19 08:20:03 +00001001/* Notes on fetching login data from wtmp/wtmpx
1002 *
1003 * Logouts are usually recorded with (amongst other things) a blank
1004 * username on a given tty line. However, some systems (HP-UX is one)
1005 * leave all fields set, but change the ut_type field to DEAD_PROCESS.
1006 *
1007 * Since we're only looking for logins here, we know that the username
1008 * must be set correctly. On systems that leave it in, we check for
1009 * ut_type==USER_PROCESS (indicating a login.)
1010 *
1011 * Portability: Some systems may set something other than USER_PROCESS
1012 * to indicate a login process. I don't know of any as I write. Also,
1013 * it's possible that some systems may both leave the username in
1014 * place and not have ut_type.
1015 */
1016
andre6bb92372000-06-19 08:20:03 +00001017/* return true if this wtmp entry indicates a login */
1018static int
1019wtmp_islogin(struct logininfo *li, struct utmp *ut)
1020{
Damien Miller7a0e5dc2000-07-11 12:15:54 +10001021 if (strncmp(li->username, ut->ut_name,
1022 MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001023# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001024 if (ut->ut_type & USER_PROCESS)
1025 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001026# else
andre6bb92372000-06-19 08:20:03 +00001027 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001028# endif
andre6bb92372000-06-19 08:20:03 +00001029 }
1030 return 0;
1031}
1032
andre2ff7b5d2000-06-03 14:57:40 +00001033int
andre61e67252000-06-04 17:07:49 +00001034wtmp_get_entry(struct logininfo *li)
1035{
andre2ff7b5d2000-06-03 14:57:40 +00001036 struct stat st;
1037 struct utmp ut;
andre6bb92372000-06-19 08:20:03 +00001038 int fd, found=0;
1039
1040 /* Clear the time entries in our logininfo */
1041 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001042
1043 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1044 log("wtmp_get_entry: problem opening %s: %s",
1045 WTMP_FILE, strerror(errno));
1046 return 0;
1047 }
andre61e67252000-06-04 17:07:49 +00001048 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001049 log("wtmp_get_entry: couldn't stat %s: %s",
1050 WTMP_FILE, strerror(errno));
1051 close(fd);
1052 return 0;
1053 }
andre2ff7b5d2000-06-03 14:57:40 +00001054
andre6bb92372000-06-19 08:20:03 +00001055 /* Seek to the start of the last struct utmp */
Damien Miller348c9b72000-08-15 10:01:22 +10001056 if (lseek(fd, (off_t)(0 - sizeof(struct utmp)), SEEK_END) == -1) {
andre6bb92372000-06-19 08:20:03 +00001057 /* Looks like we've got a fresh wtmp file */
1058 close(fd);
1059 return 0;
1060 }
1061
1062 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001063 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
andre2ff7b5d2000-06-03 14:57:40 +00001064 log("wtmp_get_entry: read of %s failed: %s",
1065 WTMP_FILE, strerror(errno));
1066 close (fd);
1067 return 0;
1068 }
andre6bb92372000-06-19 08:20:03 +00001069 if ( wtmp_islogin(li, &ut) ) {
1070 found = 1;
1071 /* We've already checked for a time in struct
1072 * utmp, in login_getlast(). */
Damien Millerdd47aa22000-06-27 11:18:27 +10001073# ifdef HAVE_TIME_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +00001074 li->tv_sec = ut.ut_time;
Damien Millerdd47aa22000-06-27 11:18:27 +10001075# else
andre2ff7b5d2000-06-03 14:57:40 +00001076# if HAVE_TV_IN_UTMP
1077 li->tv_sec = ut.ut_tv.tv_sec;
1078# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001079# endif
andre6bb92372000-06-19 08:20:03 +00001080 line_fullname(li->line, ut.ut_line,
1081 MIN_SIZEOF(li->line, ut.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001082# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001083 strlcpy(li->hostname, ut.ut_host,
1084 MIN_SIZEOF(li->hostname, ut.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001085# endif
andre6bb92372000-06-19 08:20:03 +00001086 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001087 }
andre6bb92372000-06-19 08:20:03 +00001088 /* Seek back 2 x struct utmp */
andre2ff7b5d2000-06-03 14:57:40 +00001089 if (lseek(fd, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1) {
andre6bb92372000-06-19 08:20:03 +00001090 /* We've found the start of the file, so quit */
andre2ff7b5d2000-06-03 14:57:40 +00001091 close (fd);
1092 return 0;
1093 }
andre6bb92372000-06-19 08:20:03 +00001094 }
1095
1096 /* We found an entry. Tidy up and return */
1097 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001098 return 1;
andre61e67252000-06-04 17:07:49 +00001099}
Damien Millerdd47aa22000-06-27 11:18:27 +10001100# endif /* USE_WTMP */
andre2ff7b5d2000-06-03 14:57:40 +00001101
1102
1103/**
andre61e67252000-06-04 17:07:49 +00001104 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +00001105 **/
1106
1107#ifdef USE_WTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001108/* write a wtmpx entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +00001109/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +00001110static int
andre61e67252000-06-04 17:07:49 +00001111wtmpx_write(struct logininfo *li, struct utmpx *utx)
1112{
andre2ff7b5d2000-06-03 14:57:40 +00001113 struct stat buf;
1114 int fd, ret = 1;
1115
1116 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1117 log("wtmpx_write: problem opening %s: %s",
1118 WTMPX_FILE, strerror(errno));
1119 return 0;
1120 }
1121
1122 if (fstat(fd, &buf) == 0)
Damien Miller53c5d462000-06-28 00:50:50 +10001123 if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
andre2ff7b5d2000-06-03 14:57:40 +00001124 ftruncate(fd, buf.st_size);
1125 log("wtmpx_write: problem writing %s: %s",
1126 WTMPX_FILE, strerror(errno));
1127 ret = 0;
1128 }
1129 (void)close(fd);
1130
1131 return ret;
andre61e67252000-06-04 17:07:49 +00001132}
andre2ff7b5d2000-06-03 14:57:40 +00001133
1134
1135static int
andre61e67252000-06-04 17:07:49 +00001136wtmpx_perform_login(struct logininfo *li)
1137{
andre2ff7b5d2000-06-03 14:57:40 +00001138 struct utmpx utx;
1139
1140 construct_utmpx(li, &utx);
1141 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001142}
andre2ff7b5d2000-06-03 14:57:40 +00001143
1144
1145static int
andre61e67252000-06-04 17:07:49 +00001146wtmpx_perform_logout(struct logininfo *li)
1147{
andre2ff7b5d2000-06-03 14:57:40 +00001148 struct utmpx utx;
1149
1150 construct_utmpx(li, &utx);
andre2ff7b5d2000-06-03 14:57:40 +00001151 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001152}
andre2ff7b5d2000-06-03 14:57:40 +00001153
1154
1155int
andre61e67252000-06-04 17:07:49 +00001156wtmpx_write_entry(struct logininfo *li)
1157{
andre2ff7b5d2000-06-03 14:57:40 +00001158 switch(li->type) {
1159 case LTYPE_LOGIN:
1160 return wtmpx_perform_login(li);
1161 case LTYPE_LOGOUT:
1162 return wtmpx_perform_logout(li);
1163 default:
1164 log("wtmpx_write_entry: invalid type field");
1165 return 0;
1166 }
andre61e67252000-06-04 17:07:49 +00001167}
andre2ff7b5d2000-06-03 14:57:40 +00001168
andre6bb92372000-06-19 08:20:03 +00001169/* Please see the notes above wtmp_islogin() for information about the
1170 next two functions */
1171
1172/* Return true if this wtmpx entry indicates a login */
1173static int
1174wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1175{
Damien Miller7a0e5dc2000-07-11 12:15:54 +10001176 if ( strncmp(li->username, utx->ut_name,
1177 MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001178# ifdef HAVE_TYPE_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001179 if (utx->ut_type == USER_PROCESS)
1180 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001181# else
andre6bb92372000-06-19 08:20:03 +00001182 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001183# endif
andre6bb92372000-06-19 08:20:03 +00001184 }
1185 return 0;
1186}
1187
andre2ff7b5d2000-06-03 14:57:40 +00001188
1189int
andre61e67252000-06-04 17:07:49 +00001190wtmpx_get_entry(struct logininfo *li)
1191{
andre2ff7b5d2000-06-03 14:57:40 +00001192 struct stat st;
1193 struct utmpx utx;
andre6bb92372000-06-19 08:20:03 +00001194 int fd, found=0;
1195
1196 /* Clear the time entries */
1197 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001198
1199 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1200 log("wtmpx_get_entry: problem opening %s: %s",
1201 WTMPX_FILE, strerror(errno));
1202 return 0;
1203 }
andre61e67252000-06-04 17:07:49 +00001204 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001205 log("wtmpx_get_entry: couldn't stat %s: %s",
1206 WTMP_FILE, strerror(errno));
1207 close(fd);
1208 return 0;
1209 }
andre6bb92372000-06-19 08:20:03 +00001210
1211 /* Seek to the start of the last struct utmpx */
1212 if (lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END) == -1 ) {
1213 /* probably a newly rotated wtmpx file */
1214 close(fd);
1215 return 0;
1216 }
andre2ff7b5d2000-06-03 14:57:40 +00001217
andre6bb92372000-06-19 08:20:03 +00001218 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001219 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
andre2ff7b5d2000-06-03 14:57:40 +00001220 log("wtmpx_get_entry: read of %s failed: %s",
1221 WTMPX_FILE, strerror(errno));
1222 close (fd);
1223 return 0;
1224 }
andre2ff7b5d2000-06-03 14:57:40 +00001225 /* Logouts are recorded as a blank username on a particular line.
1226 * So, we just need to find the username in struct utmpx */
andre6bb92372000-06-19 08:20:03 +00001227 if ( wtmpx_islogin(li, &utx) ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001228# ifdef HAVE_TV_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001229 li->tv_sec = utx.ut_tv.tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +10001230# else
andre2ff7b5d2000-06-03 14:57:40 +00001231# ifdef HAVE_TIME_IN_UTMPX
1232 li->tv_sec = utx.ut_time;
1233# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001234# endif
Damien Miller1a132252000-06-13 21:23:17 +10001235 line_fullname(li->line, utx.ut_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001236# ifdef HAVE_HOST_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001237 strlcpy(li->hostname, utx.ut_host,
1238 MIN_SIZEOF(li->hostname, utx.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001239# endif
andre6bb92372000-06-19 08:20:03 +00001240 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001241 }
1242 if (lseek(fd, (off_t)(0-2*sizeof(struct utmpx)), SEEK_CUR) == -1) {
1243 close (fd);
1244 return 0;
1245 }
andre6bb92372000-06-19 08:20:03 +00001246 }
1247
1248 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001249 return 1;
andre61e67252000-06-04 17:07:49 +00001250}
Damien Millerd5bf3072000-06-07 21:32:13 +10001251#endif /* USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001252
andre2ff7b5d2000-06-03 14:57:40 +00001253/**
andre61e67252000-06-04 17:07:49 +00001254 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001255 **/
1256
1257#ifdef USE_LOGIN
andre2ff7b5d2000-06-03 14:57:40 +00001258static int
andre61e67252000-06-04 17:07:49 +00001259syslogin_perform_login(struct logininfo *li)
1260{
andre2ff7b5d2000-06-03 14:57:40 +00001261 struct utmp *ut;
1262
Damien Miller348c9b72000-08-15 10:01:22 +10001263 if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
andre2ff7b5d2000-06-03 14:57:40 +00001264 log("syslogin_perform_login: couldn't malloc()");
1265 return 0;
1266 }
1267 construct_utmp(li, ut);
1268 login(ut);
1269
1270 return 1;
andre61e67252000-06-04 17:07:49 +00001271}
1272
andre2ff7b5d2000-06-03 14:57:40 +00001273static int
andre61e67252000-06-04 17:07:49 +00001274syslogin_perform_logout(struct logininfo *li)
1275{
Damien Millerdd47aa22000-06-27 11:18:27 +10001276# ifdef HAVE_LOGOUT
andre2ff7b5d2000-06-03 14:57:40 +00001277 char line[8];
1278
1279 (void)line_stripname(line, li->line, sizeof(line));
1280
1281 if (!logout(line)) {
1282 log("syslogin_perform_logout: logout() returned an error");
Damien Millerdd47aa22000-06-27 11:18:27 +10001283# ifdef HAVE_LOGWTMP
andre2ff7b5d2000-06-03 14:57:40 +00001284 } else {
1285 logwtmp(line, "", "");
Damien Millerdd47aa22000-06-27 11:18:27 +10001286# endif
Damien Miller9b6d4ab2000-07-02 08:43:18 +10001287 }
andre6bb92372000-06-19 08:20:03 +00001288 /* FIXME: (ATL - if the need arises) What to do if we have
1289 * login, but no logout? what if logout but no logwtmp? All
1290 * routines are in libutil so they should all be there,
1291 * but... */
Damien Millerdd47aa22000-06-27 11:18:27 +10001292# endif
andre2ff7b5d2000-06-03 14:57:40 +00001293 return 1;
andre61e67252000-06-04 17:07:49 +00001294}
andre2ff7b5d2000-06-03 14:57:40 +00001295
andre2ff7b5d2000-06-03 14:57:40 +00001296int
andre61e67252000-06-04 17:07:49 +00001297syslogin_write_entry(struct logininfo *li)
1298{
andre2ff7b5d2000-06-03 14:57:40 +00001299 switch (li->type) {
1300 case LTYPE_LOGIN:
1301 return syslogin_perform_login(li);
1302 case LTYPE_LOGOUT:
1303 return syslogin_perform_logout(li);
1304 default:
1305 log("syslogin_write_entry: Invalid type field");
1306 return 0;
1307 }
andre61e67252000-06-04 17:07:49 +00001308}
Damien Millerd5bf3072000-06-07 21:32:13 +10001309#endif /* USE_LOGIN */
andre2ff7b5d2000-06-03 14:57:40 +00001310
1311/* end of file log-syslogin.c */
1312
andre2ff7b5d2000-06-03 14:57:40 +00001313/**
andre61e67252000-06-04 17:07:49 +00001314 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001315 **/
1316
1317#ifdef USE_LASTLOG
Damien Millerdd47aa22000-06-27 11:18:27 +10001318#define LL_FILE 1
1319#define LL_DIR 2
1320#define LL_OTHER 3
andre2ff7b5d2000-06-03 14:57:40 +00001321
andre2ff7b5d2000-06-03 14:57:40 +00001322static void
andre61e67252000-06-04 17:07:49 +00001323lastlog_construct(struct logininfo *li, struct lastlog *last)
1324{
andre2ff7b5d2000-06-03 14:57:40 +00001325 /* clear the structure */
Damien Miller348c9b72000-08-15 10:01:22 +10001326 memset(last, '\0', sizeof(*last));
andre2ff7b5d2000-06-03 14:57:40 +00001327
Damien Millerdd47aa22000-06-27 11:18:27 +10001328 (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
andre6bb92372000-06-19 08:20:03 +00001329 strlcpy(last->ll_host, li->hostname,
1330 MIN_SIZEOF(last->ll_host, li->hostname));
andre2ff7b5d2000-06-03 14:57:40 +00001331 last->ll_time = li->tv_sec;
andre61e67252000-06-04 17:07:49 +00001332}
andre2ff7b5d2000-06-03 14:57:40 +00001333
andre2ff7b5d2000-06-03 14:57:40 +00001334static int
andre61e67252000-06-04 17:07:49 +00001335lastlog_filetype(char *filename)
1336{
andre2ff7b5d2000-06-03 14:57:40 +00001337 struct stat st;
1338
Damien Millerdd47aa22000-06-27 11:18:27 +10001339 if (stat(LASTLOG_FILE, &st) != 0) {
1340 log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
1341 strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +00001342 return 0;
1343 }
andre2ff7b5d2000-06-03 14:57:40 +00001344 if (S_ISDIR(st.st_mode))
1345 return LL_DIR;
1346 else if (S_ISREG(st.st_mode))
1347 return LL_FILE;
1348 else
1349 return LL_OTHER;
andre61e67252000-06-04 17:07:49 +00001350}
andre2ff7b5d2000-06-03 14:57:40 +00001351
1352
1353/* open the file (using filemode) and seek to the login entry */
1354static int
andre61e67252000-06-04 17:07:49 +00001355lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1356{
andre2ff7b5d2000-06-03 14:57:40 +00001357 off_t offset;
1358 int type;
1359 char lastlog_file[1024];
1360
1361 type = lastlog_filetype(LASTLOG_FILE);
1362 switch (type) {
Damien Millerf8af08d2000-06-27 09:40:06 +10001363 case LL_FILE:
1364 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1365 break;
1366 case LL_DIR:
1367 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1368 LASTLOG_FILE, li->username);
1369 break;
1370 default:
1371 log("lastlog_openseek: %.100s is not a file or directory!",
1372 LASTLOG_FILE);
1373 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001374 }
andre2ff7b5d2000-06-03 14:57:40 +00001375
1376 *fd = open(lastlog_file, filemode);
1377 if ( *fd < 0) {
Damien Miller53c5d462000-06-28 00:50:50 +10001378 debug("lastlog_openseek: Couldn't open %s: %s",
andre2ff7b5d2000-06-03 14:57:40 +00001379 lastlog_file, strerror(errno));
1380 return 0;
1381 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001382
Damien Millere477ef62000-08-15 10:21:17 +10001383 if (type == LL_FILE) {
1384 /* find this uid's offset in the lastlog file */
1385 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
andre2ff7b5d2000-06-03 14:57:40 +00001386
Damien Millere477ef62000-08-15 10:21:17 +10001387 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1388 log("lastlog_openseek: %s->lseek(): %s",
1389 lastlog_file, strerror(errno));
1390 return 0;
1391 }
andre2ff7b5d2000-06-03 14:57:40 +00001392 }
Damien Millere477ef62000-08-15 10:21:17 +10001393
andre2ff7b5d2000-06-03 14:57:40 +00001394 return 1;
andre61e67252000-06-04 17:07:49 +00001395}
andre2ff7b5d2000-06-03 14:57:40 +00001396
1397static int
andre61e67252000-06-04 17:07:49 +00001398lastlog_perform_login(struct logininfo *li)
1399{
andre2ff7b5d2000-06-03 14:57:40 +00001400 struct lastlog last;
1401 int fd;
1402
1403 /* create our struct lastlog */
1404 lastlog_construct(li, &last);
1405
Damien Millerc1132e72000-08-18 14:08:38 +10001406 if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
1407 return(0);
1408
andre2ff7b5d2000-06-03 14:57:40 +00001409 /* write the entry */
Damien Millerc1132e72000-08-18 14:08:38 +10001410 if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
1411 close(fd);
1412 log("lastlog_write_filemode: Error writing to %s: %s",
1413 LASTLOG_FILE, strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +00001414 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001415 }
Damien Millerc1132e72000-08-18 14:08:38 +10001416
1417 close(fd);
1418 return 1;
andre61e67252000-06-04 17:07:49 +00001419}
andre2ff7b5d2000-06-03 14:57:40 +00001420
andre2ff7b5d2000-06-03 14:57:40 +00001421int
andre61e67252000-06-04 17:07:49 +00001422lastlog_write_entry(struct logininfo *li)
1423{
andre2ff7b5d2000-06-03 14:57:40 +00001424 switch(li->type) {
1425 case LTYPE_LOGIN:
1426 return lastlog_perform_login(li);
1427 default:
1428 log("lastlog_write_entry: Invalid type field");
1429 return 0;
1430 }
andre61e67252000-06-04 17:07:49 +00001431}
andre2ff7b5d2000-06-03 14:57:40 +00001432
andre2ff7b5d2000-06-03 14:57:40 +00001433static void
andre61e67252000-06-04 17:07:49 +00001434lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1435{
andre2ff7b5d2000-06-03 14:57:40 +00001436 line_fullname(li->line, last->ll_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001437 strlcpy(li->hostname, last->ll_host,
andre6bb92372000-06-19 08:20:03 +00001438 MIN_SIZEOF(li->hostname, last->ll_host));
andre2ff7b5d2000-06-03 14:57:40 +00001439 li->tv_sec = last->ll_time;
andre61e67252000-06-04 17:07:49 +00001440}
andre2ff7b5d2000-06-03 14:57:40 +00001441
andre2ff7b5d2000-06-03 14:57:40 +00001442int
andre61e67252000-06-04 17:07:49 +00001443lastlog_get_entry(struct logininfo *li)
1444{
andre2ff7b5d2000-06-03 14:57:40 +00001445 struct lastlog last;
1446 int fd;
1447
1448 if (lastlog_openseek(li, &fd, O_RDONLY)) {
Damien Miller53c5d462000-06-28 00:50:50 +10001449 if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
1450 log("lastlog_get_entry: Error reading from %s: %s",
andre2ff7b5d2000-06-03 14:57:40 +00001451 LASTLOG_FILE, strerror(errno));
1452 return 0;
1453 } else {
1454 lastlog_populate_entry(li, &last);
1455 return 1;
1456 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001457 } else {
andre2ff7b5d2000-06-03 14:57:40 +00001458 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001459 }
andre61e67252000-06-04 17:07:49 +00001460}
Damien Millerd5bf3072000-06-07 21:32:13 +10001461#endif /* USE_LASTLOG */