blob: 5b487eb70753c6a75543804f6964f4e524f3ebbf [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
andre61e67252000-06-04 17:07:49 +0000159#if HAVE_UTMP_H
160# include <utmp.h>
161#endif
162#if HAVE_UTMPX_H
163# include <utmpx.h>
164#endif
165#if HAVE_LASTLOG_H
166# include <lastlog.h>
167#endif
andre2ff7b5d2000-06-03 14:57:40 +0000168
169#include "ssh.h"
170#include "xmalloc.h"
171#include "loginrec.h"
172
Damien Millerdd47aa22000-06-27 11:18:27 +1000173RCSID("$Id: loginrec.c,v 1.11 2000/06/27 01:18:27 djm Exp $");
andre2ff7b5d2000-06-03 14:57:40 +0000174
175/**
176 ** prototypes for helper functions in this file
177 **/
178
179#if HAVE_UTMP_H
andre2ff7b5d2000-06-03 14:57:40 +0000180void set_utmp_time(struct logininfo *li, struct utmp *ut);
181void construct_utmp(struct logininfo *li, struct utmp *ut);
182#endif
183
184#ifdef HAVE_UTMPX_H
andre2ff7b5d2000-06-03 14:57:40 +0000185void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
186void construct_utmpx(struct logininfo *li, struct utmpx *ut);
187#endif
188
189int utmp_write_entry(struct logininfo *li);
190int utmpx_write_entry(struct logininfo *li);
191int wtmp_write_entry(struct logininfo *li);
192int wtmpx_write_entry(struct logininfo *li);
193int lastlog_write_entry(struct logininfo *li);
194int syslogin_write_entry(struct logininfo *li);
195
196int getlast_entry(struct logininfo *li);
197int lastlog_get_entry(struct logininfo *li);
198int wtmp_get_entry(struct logininfo *li);
199int wtmpx_get_entry(struct logininfo *li);
200
andre6bb92372000-06-19 08:20:03 +0000201/* pick the shortest string */
202#define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
203
andre2ff7b5d2000-06-03 14:57:40 +0000204/**
205 ** platform-independent login functions
206 **/
207
andre6bb92372000-06-19 08:20:03 +0000208/* login_login(struct logininfo *) -Record a login
209 *
210 * Call with a pointer to a struct logininfo initialised with
211 * login_init_entry() or login_alloc_entry()
212 *
213 * Returns:
214 * >0 if successful
215 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
216 */
andre61e67252000-06-04 17:07:49 +0000217int
218login_login (struct logininfo *li)
219{
220 li->type = LTYPE_LOGIN;
221 return login_write(li);
222}
223
224
andre6bb92372000-06-19 08:20:03 +0000225/* login_logout(struct logininfo *) - Record a logout
226 *
227 * Call as with login_login()
228 *
229 * Returns:
230 * >0 if successful
231 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
232 */
andre61e67252000-06-04 17:07:49 +0000233int
234login_logout(struct logininfo *li)
235{
236 li->type = LTYPE_LOGOUT;
237 return login_write(li);
238}
239
andre6bb92372000-06-19 08:20:03 +0000240/* login_get_lastlog_time(int) - Retrieve the last login time
241 *
242 * Retrieve the last login time for the given uid. Will try to use the
243 * system lastlog facilities if they are available, but will fall back
244 * to looking in wtmp/wtmpx if necessary
245 *
246 * Returns:
247 * 0 on failure, or if user has never logged in
248 * Time in seconds from the epoch if successful
249 *
250 * Useful preprocessor symbols:
251 * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
252 * info
253 * USE_LASTLOG: If set, indicates the presence of system lastlog
254 * facilities. If this and DISABLE_LASTLOG are not set,
255 * try to retrieve lastlog information from wtmp/wtmpx.
256 */
andre61e67252000-06-04 17:07:49 +0000257unsigned int
258login_get_lastlog_time(const int uid)
259{
260 struct logininfo li;
261
andre6bb92372000-06-19 08:20:03 +0000262 if (login_get_lastlog(&li, uid))
263 return li.tv_sec;
264 else
265 return 0;
andre61e67252000-06-04 17:07:49 +0000266}
267
andre6bb92372000-06-19 08:20:03 +0000268/* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
269 *
270 * Retrieve a logininfo structure populated (only partially) with
271 * information from the system lastlog data, or from wtmp/wtmpx if no
272 * system lastlog information exists.
273 *
274 * Note this routine must be given a pre-allocated logininfo.
275 *
276 * Returns:
277 * >0: A pointer to your struct logininfo if successful
278 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
279 *
280 */
andre61e67252000-06-04 17:07:49 +0000281struct logininfo *
282login_get_lastlog(struct logininfo *li, const int uid)
283{
andre6bb92372000-06-19 08:20:03 +0000284#ifndef USE_LASTLOG
285 struct passwd *pw;
286#endif
287
andre61e67252000-06-04 17:07:49 +0000288 memset(li, '\0', sizeof(struct logininfo));
289 li->uid = uid;
andre6bb92372000-06-19 08:20:03 +0000290
291#ifndef USE_LASTLOG
292 /* If we don't have a 'real' lastlog, we need the username to
293 * reliably search wtmp(x) for the last login (see
294 * wtmp_get_entry().) */
295 pw = getpwuid(uid);
Damien Millerdd47aa22000-06-27 11:18:27 +1000296 if (pw == NULL)
297 fatal("login_get_lastlog: Cannot find account for uid %i", uid);
298
andre98cabe02000-06-19 09:11:30 +0000299 /* No MIN_SIZEOF here - we absolutely *must not* truncate the
300 * username */
Damien Millerf8af08d2000-06-27 09:40:06 +1000301 strlcpy(li->username, pw->pw_name, sizeof(li->username));
andre6bb92372000-06-19 08:20:03 +0000302#endif
Damien Millerdd47aa22000-06-27 11:18:27 +1000303
andre61e67252000-06-04 17:07:49 +0000304 if (getlast_entry(li))
305 return li;
306 else
Damien Millerdd47aa22000-06-27 11:18:27 +1000307 return NULL;
andre61e67252000-06-04 17:07:49 +0000308}
309
310
andre6bb92372000-06-19 08:20:03 +0000311/* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise
312 * a logininfo structure
313 *
314 * This function creates a new struct logininfo, a data structure
315 * meant to carry the information required to portably record login info.
316 *
317 * Returns a pointer to a newly created struct logininfo. If memory
318 * allocation fails, the program halts.
319 */
andre61e67252000-06-04 17:07:49 +0000320struct
321logininfo *login_alloc_entry(int pid, const char *username,
322 const char *hostname, const char *line)
323{
andre2ff7b5d2000-06-03 14:57:40 +0000324 struct logininfo *newli;
325
326 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo));
andre61e67252000-06-04 17:07:49 +0000327 (void)login_init_entry(newli, pid, username, hostname, line);
328 return newli;
329}
andre2ff7b5d2000-06-03 14:57:40 +0000330
331
andre6bb92372000-06-19 08:20:03 +0000332/* login_free_entry(struct logininfo *) - free struct memory */
andre61e67252000-06-04 17:07:49 +0000333void
334login_free_entry(struct logininfo *li)
335{
336 xfree(li);
337}
338
andre2ff7b5d2000-06-03 14:57:40 +0000339
andre6bb92372000-06-19 08:20:03 +0000340/* login_init_entry(struct logininfo *, int, char*, char*, char*)
341 * - initialise a struct logininfo
342 *
343 * Populates a new struct logininfo, a data structure meant to carry
344 * the information required to portably record login info.
345 *
346 * Returns: 1
347 */
andre61e67252000-06-04 17:07:49 +0000348int
349login_init_entry(struct logininfo *li, int pid, const char *username,
350 const char *hostname, const char *line)
351{
Damien Millerf8af08d2000-06-27 09:40:06 +1000352 struct passwd *pw;
353
andre2ff7b5d2000-06-03 14:57:40 +0000354 memset(li, 0, sizeof(struct logininfo));
355
andre61e67252000-06-04 17:07:49 +0000356 li->pid = pid;
Damien Millerf8af08d2000-06-27 09:40:06 +1000357
andre2ff7b5d2000-06-03 14:57:40 +0000358 /* set the line information */
andre61e67252000-06-04 17:07:49 +0000359 if (line)
andre2ff7b5d2000-06-03 14:57:40 +0000360 line_fullname(li->line, line, sizeof(li->line));
andre2ff7b5d2000-06-03 14:57:40 +0000361
Damien Millerf8af08d2000-06-27 09:40:06 +1000362 if (username) {
andre2ff7b5d2000-06-03 14:57:40 +0000363 strlcpy(li->username, username, sizeof(li->username));
Damien Millerf8af08d2000-06-27 09:40:06 +1000364 pw = getpwnam(li->username);
365 if (pw == NULL)
366 fatal("login_init_entry: Cannot find user \"%s\"", li->username);
367 li->uid = pw->pw_uid;
368 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000369
andre61e67252000-06-04 17:07:49 +0000370 if (hostname)
andre2ff7b5d2000-06-03 14:57:40 +0000371 strlcpy(li->hostname, hostname, sizeof(li->hostname));
Damien Millerf8af08d2000-06-27 09:40:06 +1000372
andre61e67252000-06-04 17:07:49 +0000373 return 1;
andre2ff7b5d2000-06-03 14:57:40 +0000374}
375
andre6bb92372000-06-19 08:20:03 +0000376/* login_set_current_time(struct logininfo *) - set the current time
377 *
378 * Set the current time in a logininfo structure. This function is
379 * meant to eliminate the need to deal with system dependencies for
380 * time handling.
381 */
andre2ff7b5d2000-06-03 14:57:40 +0000382void
andre61e67252000-06-04 17:07:49 +0000383login_set_current_time(struct logininfo *li)
384{
andre2ff7b5d2000-06-03 14:57:40 +0000385 struct timeval tv;
386
387 gettimeofday(&tv, NULL);
Damien Millerf8af08d2000-06-27 09:40:06 +1000388
389 li->tv_sec = tv.tv_sec;
390 li->tv_usec = tv.tv_usec;
andre2ff7b5d2000-06-03 14:57:40 +0000391}
392
andre61e67252000-06-04 17:07:49 +0000393/* copy a sockaddr_* into our logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000394void
andre61e67252000-06-04 17:07:49 +0000395login_set_addr(struct logininfo *li, const struct sockaddr *sa,
396 const unsigned int sa_size)
397{
398 unsigned int bufsize = sa_size;
399
400 /* make sure we don't overrun our union */
401 if (sizeof(li->hostaddr) < sa_size)
402 bufsize = sizeof(li->hostaddr);
403
404 memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
andre2ff7b5d2000-06-03 14:57:40 +0000405}
406
andre2ff7b5d2000-06-03 14:57:40 +0000407
andre61e67252000-06-04 17:07:49 +0000408/**
409 ** login_write: Call low-level recording functions based on autoconf
410 ** results
411 **/
andre2ff7b5d2000-06-03 14:57:40 +0000412int
andre61e67252000-06-04 17:07:49 +0000413login_write (struct logininfo *li)
414{
andre2ff7b5d2000-06-03 14:57:40 +0000415 if ((int)geteuid() != 0) {
416 log("Attempt to write login records by non-root user (aborting)");
417 return 1;
418 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000419
andre2ff7b5d2000-06-03 14:57:40 +0000420 /* set the timestamp */
421 login_set_current_time(li);
422#ifdef USE_LOGIN
423 syslogin_write_entry(li);
424#endif
425#ifdef USE_LASTLOG
426 if (li->type == LTYPE_LOGIN) {
427 lastlog_write_entry(li);
428 }
429#endif
430#ifdef USE_UTMP
431 utmp_write_entry(li);
432#endif
433#ifdef USE_WTMP
434 wtmp_write_entry(li);
435#endif
436#ifdef USE_UTMPX
437 utmpx_write_entry(li);
438#endif
439#ifdef USE_WTMPX
440 wtmpx_write_entry(li);
441#endif
442 return 0;
443}
444
andre2ff7b5d2000-06-03 14:57:40 +0000445/**
andre61e67252000-06-04 17:07:49 +0000446 ** getlast_entry: Call low-level functions to retrieve the last login
447 ** time.
andre2ff7b5d2000-06-03 14:57:40 +0000448 **/
449
andre61e67252000-06-04 17:07:49 +0000450/* take the uid in li and return the last login time */
451int
452getlast_entry(struct logininfo *li)
453{
454#ifdef USE_LASTLOG
455 if (lastlog_get_entry(li))
456 return 1;
457 else
458 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +1000459#else /* !USE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000460
Damien Millerdd47aa22000-06-27 11:18:27 +1000461#ifdef DISABLE_LASTLOG
andreecaabf12000-06-12 22:21:44 +0000462 /* On some systems we shouldn't even try to obtain last login
463 * time, e.g. AIX */
464 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +1000465# else /* DISABLE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000466 /* Try to retrieve the last login time from wtmp */
Damien Millerdd47aa22000-06-27 11:18:27 +1000467# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
andre61e67252000-06-04 17:07:49 +0000468 /* retrieve last login time from utmp */
Damien Millerdd47aa22000-06-27 11:18:27 +1000469 return (wtmp_get_entry(li));
470# else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
andre61e67252000-06-04 17:07:49 +0000471 /* If wtmp isn't available, try wtmpx */
Damien Millerdd47aa22000-06-27 11:18:27 +1000472# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
andre61e67252000-06-04 17:07:49 +0000473 /* retrieve last login time from utmpx */
Damien Millerdd47aa22000-06-27 11:18:27 +1000474 return (wtmpx_get_entry(li));
475# else
andre61e67252000-06-04 17:07:49 +0000476 /* Give up: No means of retrieving last login time */
477 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +1000478# endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
479# endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
480# endif /* DISABLE_LASTLOG */
481#endif /* USE_LASTLOG */
andre61e67252000-06-04 17:07:49 +0000482}
483
484
485
andre2ff7b5d2000-06-03 14:57:40 +0000486/*
andre61e67252000-06-04 17:07:49 +0000487 * 'line' string utility functions
488 *
489 * These functions process the 'line' string into one of three forms:
490 *
andre2ff7b5d2000-06-03 14:57:40 +0000491 * 1. The full filename (including '/dev')
492 * 2. The stripped name (excluding '/dev')
andre61e67252000-06-04 17:07:49 +0000493 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
494 * /dev/pts/1 -> ts/1 )
andre2ff7b5d2000-06-03 14:57:40 +0000495 *
496 * Form 3 is used on some systems to identify a .tmp.? entry when
497 * attempting to remove it. Typically both addition and removal is
andre61e67252000-06-04 17:07:49 +0000498 * performed by one application - say, sshd - so as long as the choice
499 * uniquely identifies a terminal it's ok.
andre2ff7b5d2000-06-03 14:57:40 +0000500 */
501
502
andre61e67252000-06-04 17:07:49 +0000503/* line_fullname(): add the leading '/dev/' if it doesn't exist make
504 * sure dst has enough space, if not just copy src (ugh) */
andre2ff7b5d2000-06-03 14:57:40 +0000505char *
andre61e67252000-06-04 17:07:49 +0000506line_fullname(char *dst, const char *src, int dstsize)
507{
andre2ff7b5d2000-06-03 14:57:40 +0000508 memset(dst, '\0', dstsize);
509 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
510 strlcpy(dst, src, dstsize);
511 else {
Damien Miller1a132252000-06-13 21:23:17 +1000512 strlcpy(dst, "/dev/", dstsize);
andre2ff7b5d2000-06-03 14:57:40 +0000513 strlcat(dst, src, dstsize);
514 }
515 return dst;
516}
517
andre61e67252000-06-04 17:07:49 +0000518/* line_stripname(): strip the leading '/dev' if it exists, return dst */
andre2ff7b5d2000-06-03 14:57:40 +0000519char *
andre61e67252000-06-04 17:07:49 +0000520line_stripname(char *dst, const char *src, int dstsize)
521{
andre2ff7b5d2000-06-03 14:57:40 +0000522 memset(dst, '\0', dstsize);
523 if (strncmp(src, "/dev/", 5) == 0)
524 strlcpy(dst, &src[5], dstsize);
525 else
526 strlcpy(dst, src, dstsize);
527 return dst;
andre61e67252000-06-04 17:07:49 +0000528}
529
andre61e67252000-06-04 17:07:49 +0000530/* line_abbrevname(): Return the abbreviated (usually four-character)
531 * form of the line (Just use the last <dstsize> characters of the
532 * full name.)
533 *
534 * NOTE: use strncpy because we do NOT necessarily want zero
535 * termination */
andre2ff7b5d2000-06-03 14:57:40 +0000536char *
Damien Millerdd47aa22000-06-27 11:18:27 +1000537line_abbrevname(char *dst, const char *src, int dstsize)
538{
539 size_t len;
540
andre2ff7b5d2000-06-03 14:57:40 +0000541 memset(dst, '\0', dstsize);
Damien Millerdd47aa22000-06-27 11:18:27 +1000542
543 len = strlen(src);
544
545 if (len <= 0) {
546 src += (len - dstsize);
547 strncpy(dst, src, dstsize); /* note: _don't_ change this to strlcpy */
548 }
549
andre2ff7b5d2000-06-03 14:57:40 +0000550 return dst;
551}
552
andre2ff7b5d2000-06-03 14:57:40 +0000553/**
554 ** utmp utility functions
andre61e67252000-06-04 17:07:49 +0000555 **
556 ** These functions manipulate struct utmp, taking system differences
557 ** into account.
andre2ff7b5d2000-06-03 14:57:40 +0000558 **/
559
560#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
561
andre2ff7b5d2000-06-03 14:57:40 +0000562/* build the utmp structure */
563void
andre61e67252000-06-04 17:07:49 +0000564set_utmp_time(struct logininfo *li, struct utmp *ut)
565{
Damien Millerdd47aa22000-06-27 11:18:27 +1000566# ifdef HAVE_TV_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000567 ut->ut_tv.tv_sec = li->tv_sec;
568 ut->ut_tv.tv_usec = li->tv_usec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000569# else
andre2ff7b5d2000-06-03 14:57:40 +0000570# ifdef HAVE_TIME_IN_UTMP
571 ut->ut_time = li->tv_sec;
572# endif
Damien Millerdd47aa22000-06-27 11:18:27 +1000573# endif
andre2ff7b5d2000-06-03 14:57:40 +0000574}
575
576void
577construct_utmp(struct logininfo *li,
andre61e67252000-06-04 17:07:49 +0000578 struct utmp *ut)
579{
andre2ff7b5d2000-06-03 14:57:40 +0000580 memset(ut, '\0', sizeof(struct utmp));
andre6bb92372000-06-19 08:20:03 +0000581
582 /* First fill out fields used for both logins and logouts */
583
Damien Millerdd47aa22000-06-27 11:18:27 +1000584# ifdef HAVE_ID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000585 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000586# endif
andre2ff7b5d2000-06-03 14:57:40 +0000587
Damien Millerdd47aa22000-06-27 11:18:27 +1000588# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +0000589 /* This is done here to keep utmp constants out of struct logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000590 switch (li->type) {
591 case LTYPE_LOGIN:
592 ut->ut_type = USER_PROCESS;
593 break;
594 case LTYPE_LOGOUT:
595 ut->ut_type = DEAD_PROCESS;
596 break;
597 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000598# endif
andre6bb92372000-06-19 08:20:03 +0000599 set_utmp_time(li, ut);
andre2ff7b5d2000-06-03 14:57:40 +0000600
andre6bb92372000-06-19 08:20:03 +0000601 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000602
603# ifdef HAVE_PID_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +0000604 ut->ut_pid = li->pid;
Damien Millerdd47aa22000-06-27 11:18:27 +1000605# endif
andre6bb92372000-06-19 08:20:03 +0000606
607 /* If we're logging out, leave all other fields blank */
608 if (li->type == LTYPE_LOGOUT)
609 return;
610
Damien Millerdd47aa22000-06-27 11:18:27 +1000611 /*
612 * These fields are only used when logging in, and are blank
613 * for logouts.
614 */
andre6bb92372000-06-19 08:20:03 +0000615
616 /* Use strncpy because we don't necessarily want null termination */
617 strncpy(ut->ut_user, li->username, MIN_SIZEOF(ut->ut_user, li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000618# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +0000619 strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000620# endif
621# ifdef HAVE_ADDR_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000622 /* this is just a 32-bit IP address */
623 if (li->hostaddr.sa.sa_family == AF_INET)
624 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
Damien Millerdd47aa22000-06-27 11:18:27 +1000625# endif
andre61e67252000-06-04 17:07:49 +0000626}
Damien Millerdd47aa22000-06-27 11:18:27 +1000627#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
andre61e67252000-06-04 17:07:49 +0000628
andre2ff7b5d2000-06-03 14:57:40 +0000629/**
630 ** utmpx utility functions
andre61e67252000-06-04 17:07:49 +0000631 **
632 ** These functions manipulate struct utmpx, accounting for system
633 ** variations.
andre2ff7b5d2000-06-03 14:57:40 +0000634 **/
635
636#if defined(USE_UTMPX) || defined (USE_WTMPX)
andre2ff7b5d2000-06-03 14:57:40 +0000637/* build the utmpx structure */
638void
andre61e67252000-06-04 17:07:49 +0000639set_utmpx_time(struct logininfo *li, struct utmpx *utx)
640{
Damien Millerdd47aa22000-06-27 11:18:27 +1000641# ifdef HAVE_TV_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000642 utx->ut_tv.tv_sec = li->tv_sec;
643 utx->ut_tv.tv_usec = li->tv_usec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000644# else /* HAVE_TV_IN_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000645# ifdef HAVE_TIME_IN_UTMPX
646 utx->ut_time = li->tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +1000647# endif /* HAVE_TIME_IN_UTMPX */
648# endif /* HAVE_TV_IN_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000649}
650
andre61e67252000-06-04 17:07:49 +0000651void
652construct_utmpx(struct logininfo *li, struct utmpx *utx)
653{
654 memset(utx, '\0', sizeof(struct utmpx));
andre2ff7b5d2000-06-03 14:57:40 +0000655 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
656
657 /* this is done here to keep utmp constants out of loginrec.h */
658 switch (li->type) {
659 case LTYPE_LOGIN:
660 utx->ut_type = USER_PROCESS;
661 break;
662 case LTYPE_LOGOUT:
663 utx->ut_type = DEAD_PROCESS;
664 break;
665 }
andre2ff7b5d2000-06-03 14:57:40 +0000666 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
andre2ff7b5d2000-06-03 14:57:40 +0000667 set_utmpx_time(li, utx);
andre6bb92372000-06-19 08:20:03 +0000668 utx->ut_pid = li->pid;
669
670 if (li->type == LTYPE_LOGOUT)
671 return;
672
Damien Millerdd47aa22000-06-27 11:18:27 +1000673 /*
674 * These fields are only used when logging in, and are blank
675 * for logouts.
676 */
andre6bb92372000-06-19 08:20:03 +0000677
678 /* strncpy(): Don't necessarily want null termination */
679 strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
Damien Millerdd47aa22000-06-27 11:18:27 +1000680# ifdef HAVE_HOST_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +0000681 strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
Damien Millerdd47aa22000-06-27 11:18:27 +1000682# endif
683# ifdef HAVE_ADDR_IN_UTMPX
andre61e67252000-06-04 17:07:49 +0000684 /* FIXME: (ATL) not supported yet */
Damien Millerdd47aa22000-06-27 11:18:27 +1000685# endif
686# ifdef HAVE_SYSLEN_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +0000687 /* ut_syslen is the length of the utx_host string */
688 utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +1000689# endif
andre61e67252000-06-04 17:07:49 +0000690}
Damien Millerdd47aa22000-06-27 11:18:27 +1000691#endif /* USE_UTMPX || USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000692
693/**
andre61e67252000-06-04 17:07:49 +0000694 ** Low-level utmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000695 **/
696
697/* FIXME: (ATL) utmp_write_direct needs testing */
andre2ff7b5d2000-06-03 14:57:40 +0000698#ifdef USE_UTMP
699
andre2ff7b5d2000-06-03 14:57:40 +0000700/* if we can, use pututline() etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000701# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
702 defined(HAVE_PUTUTLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000703# define UTMP_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000704# endif
andre2ff7b5d2000-06-03 14:57:40 +0000705
706
707/* write a utmp entry with the system's help (pututline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000708# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000709static int
andre61e67252000-06-04 17:07:49 +0000710utmp_write_library(struct logininfo *li, struct utmp *ut)
711{
andre2ff7b5d2000-06-03 14:57:40 +0000712 setutent();
713 pututline(ut);
714
Damien Millerdd47aa22000-06-27 11:18:27 +1000715# ifdef HAVE_ENDUTENT
andre2ff7b5d2000-06-03 14:57:40 +0000716 endutent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000717# endif
andre2ff7b5d2000-06-03 14:57:40 +0000718 return 1;
andre61e67252000-06-04 17:07:49 +0000719}
Damien Millerdd47aa22000-06-27 11:18:27 +1000720# else /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000721
722/* write a utmp entry direct to the file */
andre61e67252000-06-04 17:07:49 +0000723/* This is a slightly modification of code in OpenBSD's login.c */
andre2ff7b5d2000-06-03 14:57:40 +0000724static int
andre61e67252000-06-04 17:07:49 +0000725utmp_write_direct(struct logininfo *li, struct utmp *ut)
726{
andre2ff7b5d2000-06-03 14:57:40 +0000727 struct utmp old_ut;
728 register int fd;
729 int tty;
730
andre6bb92372000-06-19 08:20:03 +0000731 /* FIXME: (ATL) ttyslot() needs local implementation */
andre2ff7b5d2000-06-03 14:57:40 +0000732 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
733
734 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
735 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
736 /*
737 * Prevent luser from zero'ing out ut_host.
738 * If the new ut_line is empty but the old one is not
739 * and ut_line and ut_name match, preserve the old ut_line.
740 */
741 if ( read(fd, &old_ut, sizeof(struct utmp)) == sizeof(struct utmp)
742 && ut->ut_host[0] == '\0'
743 && old_ut.ut_host[0] != '\0'
744 && strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0
745 && strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0 )
746 (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
747
748 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
749 if (write(fd, ut, sizeof(struct utmp))==-1)
750 log("utmp_write_direct: error writing %s: %s",
andre6bb92372000-06-19 08:20:03 +0000751 UTMP_FILE, strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +0000752
753 (void)close(fd);
754 return 1;
755 } else
756 return 0;
andre61e67252000-06-04 17:07:49 +0000757}
Damien Millerdd47aa22000-06-27 11:18:27 +1000758# endif /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000759
760static int
andre61e67252000-06-04 17:07:49 +0000761utmp_perform_login(struct logininfo *li)
762{
andre2ff7b5d2000-06-03 14:57:40 +0000763 struct utmp ut;
764
765 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000766# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000767 if (!utmp_write_library(li, &ut)) {
andre6bb92372000-06-19 08:20:03 +0000768 log("utmp_perform_login: utmp_write_library() failed");
andre2ff7b5d2000-06-03 14:57:40 +0000769 return 0;
770 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000771# else
andre2ff7b5d2000-06-03 14:57:40 +0000772 if (!utmp_write_direct(li, &ut)) {
773 log("utmp_perform_login: utmp_write_direct() failed");
774 return 0;
775 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000776# endif
andre2ff7b5d2000-06-03 14:57:40 +0000777 return 1;
andre61e67252000-06-04 17:07:49 +0000778}
andre2ff7b5d2000-06-03 14:57:40 +0000779
780
781static int
andre61e67252000-06-04 17:07:49 +0000782utmp_perform_logout(struct logininfo *li)
783{
andre2ff7b5d2000-06-03 14:57:40 +0000784 struct utmp ut;
785
andre6bb92372000-06-19 08:20:03 +0000786 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000787# ifdef UTMP_USE_LIBRARY
andre6bb92372000-06-19 08:20:03 +0000788 if (!utmp_write_library(li, &ut)) {
789 log("utmp_perform_logout: utmp_write_library() failed");
790 return 0;
791 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000792# else
andre6bb92372000-06-19 08:20:03 +0000793 if (!utmp_write_direct(li, &ut)) {
794 log("utmp_perform_logout: utmp_write_direct() failed");
795 return 0;
796 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000797# endif
andre2ff7b5d2000-06-03 14:57:40 +0000798 return 1;
andre61e67252000-06-04 17:07:49 +0000799}
andre2ff7b5d2000-06-03 14:57:40 +0000800
801
802int
andre61e67252000-06-04 17:07:49 +0000803utmp_write_entry(struct logininfo *li)
804{
andre2ff7b5d2000-06-03 14:57:40 +0000805 switch(li->type) {
806 case LTYPE_LOGIN:
807 return utmp_perform_login(li);
808
809 case LTYPE_LOGOUT:
810 return utmp_perform_logout(li);
811
812 default:
813 log("utmp_write_entry: invalid type field");
814 return 0;
815 }
andre61e67252000-06-04 17:07:49 +0000816}
Damien Millerdd47aa22000-06-27 11:18:27 +1000817#endif /* USE_UTMP */
andre2ff7b5d2000-06-03 14:57:40 +0000818
819
820/**
andre61e67252000-06-04 17:07:49 +0000821 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000822 **/
823
824/* not much point if we don't want utmpx entries */
825#ifdef USE_UTMPX
826
andre2ff7b5d2000-06-03 14:57:40 +0000827/* if we have the wherewithall, use pututxline etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000828# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
829 defined(HAVE_PUTUTXLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000830# define UTMPX_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000831# endif
andre2ff7b5d2000-06-03 14:57:40 +0000832
833
834/* write a utmpx entry with the system's help (pututxline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000835# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000836static int
andre61e67252000-06-04 17:07:49 +0000837utmpx_write_library(struct logininfo *li, struct utmpx *utx)
838{
andre2ff7b5d2000-06-03 14:57:40 +0000839 setutxent();
840 pututxline(utx);
841
Damien Millerdd47aa22000-06-27 11:18:27 +1000842# ifdef HAVE_ENDUTXENT
andre2ff7b5d2000-06-03 14:57:40 +0000843 endutxent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000844# endif
andre2ff7b5d2000-06-03 14:57:40 +0000845 return 1;
andre61e67252000-06-04 17:07:49 +0000846}
andre2ff7b5d2000-06-03 14:57:40 +0000847
Damien Millerdd47aa22000-06-27 11:18:27 +1000848# else /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000849
850/* write a utmp entry direct to the file */
851static int
andre61e67252000-06-04 17:07:49 +0000852utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
853{
andre2ff7b5d2000-06-03 14:57:40 +0000854 log("utmpx_write_direct: not implemented!");
855 return 0;
andre61e67252000-06-04 17:07:49 +0000856}
Damien Millerdd47aa22000-06-27 11:18:27 +1000857# endif /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000858
859static int
andre61e67252000-06-04 17:07:49 +0000860utmpx_perform_login(struct logininfo *li)
861{
andre2ff7b5d2000-06-03 14:57:40 +0000862 struct utmpx utx;
863
864 construct_utmpx(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000865# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000866 if (!utmpx_write_library(li, &utx)) {
867 log("utmpx_perform_login: utmp_write_library() failed");
868 return 0;
869 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000870# else
andre2ff7b5d2000-06-03 14:57:40 +0000871 if (!utmpx_write_direct(li, &ut)) {
872 log("utmpx_perform_login: utmp_write_direct() failed");
873 return 0;
874 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000875# endif
andre2ff7b5d2000-06-03 14:57:40 +0000876 return 1;
andre61e67252000-06-04 17:07:49 +0000877}
andre2ff7b5d2000-06-03 14:57:40 +0000878
879
880static int
andre61e67252000-06-04 17:07:49 +0000881utmpx_perform_logout(struct logininfo *li)
882{
andre2ff7b5d2000-06-03 14:57:40 +0000883 struct utmpx utx;
884
885 memset(&utx, '\0', sizeof(utx));
886 set_utmpx_time(li, &utx);
887 line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000888# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000889 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000890# endif
891# ifdef HAVE_TYPE_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000892 utx.ut_type = DEAD_PROCESS;
Damien Millerdd47aa22000-06-27 11:18:27 +1000893# endif
andre2ff7b5d2000-06-03 14:57:40 +0000894
Damien Millerdd47aa22000-06-27 11:18:27 +1000895# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000896 utmpx_write_library(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000897# else
andre2ff7b5d2000-06-03 14:57:40 +0000898 utmpx_write_direct(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000899# endif
andre2ff7b5d2000-06-03 14:57:40 +0000900 return 1;
andre61e67252000-06-04 17:07:49 +0000901}
andre2ff7b5d2000-06-03 14:57:40 +0000902
andre2ff7b5d2000-06-03 14:57:40 +0000903int
andre61e67252000-06-04 17:07:49 +0000904utmpx_write_entry(struct logininfo *li)
905{
andre2ff7b5d2000-06-03 14:57:40 +0000906 switch(li->type) {
907 case LTYPE_LOGIN:
908 return utmpx_perform_login(li);
909 case LTYPE_LOGOUT:
910 return utmpx_perform_logout(li);
911 default:
912 log("utmpx_write_entry: invalid type field");
913 return 0;
914 }
andre61e67252000-06-04 17:07:49 +0000915}
Damien Millerdd47aa22000-06-27 11:18:27 +1000916#endif /* USE_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000917
918
919/**
andre61e67252000-06-04 17:07:49 +0000920 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000921 **/
922
923#ifdef USE_WTMP
924
andre2ff7b5d2000-06-03 14:57:40 +0000925/* write a wtmp entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000926/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000927static int
andre61e67252000-06-04 17:07:49 +0000928wtmp_write(struct logininfo *li, struct utmp *ut)
929{
andre2ff7b5d2000-06-03 14:57:40 +0000930 struct stat buf;
931 int fd, ret = 1;
932
933 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
934 log("wtmp_write: problem writing %s: %s",
935 WTMP_FILE, strerror(errno));
936 return 0;
937 }
andre61e67252000-06-04 17:07:49 +0000938 if (fstat(fd, &buf) == 0)
andre2ff7b5d2000-06-03 14:57:40 +0000939 if (write(fd, (char *)ut, sizeof(struct utmp)) !=
940 sizeof(struct utmp)) {
941 ftruncate(fd, buf.st_size);
942 log("wtmp_write: problem writing %s: %s",
943 WTMP_FILE, strerror(errno));
944 ret = 0;
945 }
946 (void)close(fd);
andre2ff7b5d2000-06-03 14:57:40 +0000947 return ret;
andre61e67252000-06-04 17:07:49 +0000948}
andre2ff7b5d2000-06-03 14:57:40 +0000949
andre2ff7b5d2000-06-03 14:57:40 +0000950static int
Damien Millerdd47aa22000-06-27 11:18:27 +1000951wtmp_perform_login(struct logininfo *li)
952{
andre2ff7b5d2000-06-03 14:57:40 +0000953 struct utmp ut;
954
955 construct_utmp(li, &ut);
956 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000957}
andre2ff7b5d2000-06-03 14:57:40 +0000958
959
960static int
andre61e67252000-06-04 17:07:49 +0000961wtmp_perform_logout(struct logininfo *li)
962{
andre2ff7b5d2000-06-03 14:57:40 +0000963 struct utmp ut;
964
965 construct_utmp(li, &ut);
andre2ff7b5d2000-06-03 14:57:40 +0000966 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000967}
andre2ff7b5d2000-06-03 14:57:40 +0000968
969
970int
andre61e67252000-06-04 17:07:49 +0000971wtmp_write_entry(struct logininfo *li)
972{
andre2ff7b5d2000-06-03 14:57:40 +0000973 switch(li->type) {
974 case LTYPE_LOGIN:
975 return wtmp_perform_login(li);
976 case LTYPE_LOGOUT:
977 return wtmp_perform_logout(li);
978 default:
979 log("wtmp_write_entry: invalid type field");
980 return 0;
981 }
andre61e67252000-06-04 17:07:49 +0000982}
andre2ff7b5d2000-06-03 14:57:40 +0000983
984
andre6bb92372000-06-19 08:20:03 +0000985/* Notes on fetching login data from wtmp/wtmpx
986 *
987 * Logouts are usually recorded with (amongst other things) a blank
988 * username on a given tty line. However, some systems (HP-UX is one)
989 * leave all fields set, but change the ut_type field to DEAD_PROCESS.
990 *
991 * Since we're only looking for logins here, we know that the username
992 * must be set correctly. On systems that leave it in, we check for
993 * ut_type==USER_PROCESS (indicating a login.)
994 *
995 * Portability: Some systems may set something other than USER_PROCESS
996 * to indicate a login process. I don't know of any as I write. Also,
997 * it's possible that some systems may both leave the username in
998 * place and not have ut_type.
999 */
1000
andre6bb92372000-06-19 08:20:03 +00001001/* return true if this wtmp entry indicates a login */
1002static int
1003wtmp_islogin(struct logininfo *li, struct utmp *ut)
1004{
Damien Millerdd47aa22000-06-27 11:18:27 +10001005 if (strncmp(li->username, ut->ut_user,
1006 MIN_SIZEOF(li->username, ut->ut_user)) == 0) {
1007# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001008 if (ut->ut_type & USER_PROCESS)
1009 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001010# else
andre6bb92372000-06-19 08:20:03 +00001011 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001012# endif
andre6bb92372000-06-19 08:20:03 +00001013 }
1014 return 0;
1015}
1016
andre2ff7b5d2000-06-03 14:57:40 +00001017int
andre61e67252000-06-04 17:07:49 +00001018wtmp_get_entry(struct logininfo *li)
1019{
andre2ff7b5d2000-06-03 14:57:40 +00001020 struct stat st;
1021 struct utmp ut;
andre6bb92372000-06-19 08:20:03 +00001022 int fd, found=0;
1023
1024 /* Clear the time entries in our logininfo */
1025 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001026
1027 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1028 log("wtmp_get_entry: problem opening %s: %s",
1029 WTMP_FILE, strerror(errno));
1030 return 0;
1031 }
andre61e67252000-06-04 17:07:49 +00001032 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001033 log("wtmp_get_entry: couldn't stat %s: %s",
1034 WTMP_FILE, strerror(errno));
1035 close(fd);
1036 return 0;
1037 }
andre2ff7b5d2000-06-03 14:57:40 +00001038
andre6bb92372000-06-19 08:20:03 +00001039 /* Seek to the start of the last struct utmp */
1040 if (lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END) == -1) {
1041 /* Looks like we've got a fresh wtmp file */
1042 close(fd);
1043 return 0;
1044 }
1045
1046 while (!found) {
andre2ff7b5d2000-06-03 14:57:40 +00001047 if (read(fd, &ut, sizeof(ut)) != sizeof(ut)) {
1048 log("wtmp_get_entry: read of %s failed: %s",
1049 WTMP_FILE, strerror(errno));
1050 close (fd);
1051 return 0;
1052 }
andre6bb92372000-06-19 08:20:03 +00001053 if ( wtmp_islogin(li, &ut) ) {
1054 found = 1;
1055 /* We've already checked for a time in struct
1056 * utmp, in login_getlast(). */
Damien Millerdd47aa22000-06-27 11:18:27 +10001057# ifdef HAVE_TIME_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +00001058 li->tv_sec = ut.ut_time;
Damien Millerdd47aa22000-06-27 11:18:27 +10001059# else
andre2ff7b5d2000-06-03 14:57:40 +00001060# if HAVE_TV_IN_UTMP
1061 li->tv_sec = ut.ut_tv.tv_sec;
1062# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001063# endif
andre6bb92372000-06-19 08:20:03 +00001064 line_fullname(li->line, ut.ut_line,
1065 MIN_SIZEOF(li->line, ut.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001066# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001067 strlcpy(li->hostname, ut.ut_host,
1068 MIN_SIZEOF(li->hostname, ut.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001069# endif
andre6bb92372000-06-19 08:20:03 +00001070 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001071 }
andre6bb92372000-06-19 08:20:03 +00001072 /* Seek back 2 x struct utmp */
andre2ff7b5d2000-06-03 14:57:40 +00001073 if (lseek(fd, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1) {
andre6bb92372000-06-19 08:20:03 +00001074 /* We've found the start of the file, so quit */
andre2ff7b5d2000-06-03 14:57:40 +00001075 close (fd);
1076 return 0;
1077 }
andre6bb92372000-06-19 08:20:03 +00001078 }
1079
1080 /* We found an entry. Tidy up and return */
1081 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001082 return 1;
andre61e67252000-06-04 17:07:49 +00001083}
Damien Millerdd47aa22000-06-27 11:18:27 +10001084# endif /* USE_WTMP */
andre2ff7b5d2000-06-03 14:57:40 +00001085
1086
1087/**
andre61e67252000-06-04 17:07:49 +00001088 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +00001089 **/
1090
1091#ifdef USE_WTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001092/* write a wtmpx entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +00001093/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +00001094static int
andre61e67252000-06-04 17:07:49 +00001095wtmpx_write(struct logininfo *li, struct utmpx *utx)
1096{
andre2ff7b5d2000-06-03 14:57:40 +00001097 struct stat buf;
1098 int fd, ret = 1;
1099
1100 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1101 log("wtmpx_write: problem opening %s: %s",
1102 WTMPX_FILE, strerror(errno));
1103 return 0;
1104 }
1105
1106 if (fstat(fd, &buf) == 0)
1107 if (write(fd, (char *)utx, sizeof(struct utmpx)) !=
1108 sizeof(struct utmpx)) {
1109 ftruncate(fd, buf.st_size);
1110 log("wtmpx_write: problem writing %s: %s",
1111 WTMPX_FILE, strerror(errno));
1112 ret = 0;
1113 }
1114 (void)close(fd);
1115
1116 return ret;
andre61e67252000-06-04 17:07:49 +00001117}
andre2ff7b5d2000-06-03 14:57:40 +00001118
1119
1120static int
andre61e67252000-06-04 17:07:49 +00001121wtmpx_perform_login(struct logininfo *li)
1122{
andre2ff7b5d2000-06-03 14:57:40 +00001123 struct utmpx utx;
1124
1125 construct_utmpx(li, &utx);
1126 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001127}
andre2ff7b5d2000-06-03 14:57:40 +00001128
1129
1130static int
andre61e67252000-06-04 17:07:49 +00001131wtmpx_perform_logout(struct logininfo *li)
1132{
andre2ff7b5d2000-06-03 14:57:40 +00001133 struct utmpx utx;
1134
1135 construct_utmpx(li, &utx);
andre2ff7b5d2000-06-03 14:57:40 +00001136 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001137}
andre2ff7b5d2000-06-03 14:57:40 +00001138
1139
1140int
andre61e67252000-06-04 17:07:49 +00001141wtmpx_write_entry(struct logininfo *li)
1142{
andre2ff7b5d2000-06-03 14:57:40 +00001143 switch(li->type) {
1144 case LTYPE_LOGIN:
1145 return wtmpx_perform_login(li);
1146 case LTYPE_LOGOUT:
1147 return wtmpx_perform_logout(li);
1148 default:
1149 log("wtmpx_write_entry: invalid type field");
1150 return 0;
1151 }
andre61e67252000-06-04 17:07:49 +00001152}
andre2ff7b5d2000-06-03 14:57:40 +00001153
andre6bb92372000-06-19 08:20:03 +00001154/* Please see the notes above wtmp_islogin() for information about the
1155 next two functions */
1156
1157/* Return true if this wtmpx entry indicates a login */
1158static int
1159wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1160{
1161 if ( strncmp(li->username, utx->ut_user,
Damien Millerdd47aa22000-06-27 11:18:27 +10001162 MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {
1163# ifdef HAVE_TYPE_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001164 if (utx->ut_type == USER_PROCESS)
1165 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001166# else
andre6bb92372000-06-19 08:20:03 +00001167 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001168# endif
andre6bb92372000-06-19 08:20:03 +00001169 }
1170 return 0;
1171}
1172
andre2ff7b5d2000-06-03 14:57:40 +00001173
1174int
andre61e67252000-06-04 17:07:49 +00001175wtmpx_get_entry(struct logininfo *li)
1176{
andre2ff7b5d2000-06-03 14:57:40 +00001177 struct stat st;
1178 struct utmpx utx;
andre6bb92372000-06-19 08:20:03 +00001179 int fd, found=0;
1180
1181 /* Clear the time entries */
1182 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001183
1184 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1185 log("wtmpx_get_entry: problem opening %s: %s",
1186 WTMPX_FILE, strerror(errno));
1187 return 0;
1188 }
andre61e67252000-06-04 17:07:49 +00001189 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001190 log("wtmpx_get_entry: couldn't stat %s: %s",
1191 WTMP_FILE, strerror(errno));
1192 close(fd);
1193 return 0;
1194 }
andre6bb92372000-06-19 08:20:03 +00001195
1196 /* Seek to the start of the last struct utmpx */
1197 if (lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END) == -1 ) {
1198 /* probably a newly rotated wtmpx file */
1199 close(fd);
1200 return 0;
1201 }
andre2ff7b5d2000-06-03 14:57:40 +00001202
andre6bb92372000-06-19 08:20:03 +00001203 while (!found) {
andre2ff7b5d2000-06-03 14:57:40 +00001204 if (read(fd, &utx, sizeof(utx)) != sizeof(utx)) {
1205 log("wtmpx_get_entry: read of %s failed: %s",
1206 WTMPX_FILE, strerror(errno));
1207 close (fd);
1208 return 0;
1209 }
andre2ff7b5d2000-06-03 14:57:40 +00001210 /* Logouts are recorded as a blank username on a particular line.
1211 * So, we just need to find the username in struct utmpx */
andre6bb92372000-06-19 08:20:03 +00001212 if ( wtmpx_islogin(li, &utx) ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001213# ifdef HAVE_TV_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001214 li->tv_sec = utx.ut_tv.tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +10001215# else
andre2ff7b5d2000-06-03 14:57:40 +00001216# ifdef HAVE_TIME_IN_UTMPX
1217 li->tv_sec = utx.ut_time;
1218# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001219# endif
Damien Miller1a132252000-06-13 21:23:17 +10001220 line_fullname(li->line, utx.ut_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001221# ifdef HAVE_HOST_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001222 strlcpy(li->hostname, utx.ut_host,
1223 MIN_SIZEOF(li->hostname, utx.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001224# endif
andre6bb92372000-06-19 08:20:03 +00001225 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001226 }
1227 if (lseek(fd, (off_t)(0-2*sizeof(struct utmpx)), SEEK_CUR) == -1) {
1228 close (fd);
1229 return 0;
1230 }
andre6bb92372000-06-19 08:20:03 +00001231 }
1232
1233 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001234 return 1;
andre61e67252000-06-04 17:07:49 +00001235}
Damien Millerd5bf3072000-06-07 21:32:13 +10001236#endif /* USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001237
andre2ff7b5d2000-06-03 14:57:40 +00001238/**
andre61e67252000-06-04 17:07:49 +00001239 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001240 **/
1241
1242#ifdef USE_LOGIN
andre2ff7b5d2000-06-03 14:57:40 +00001243static int
andre61e67252000-06-04 17:07:49 +00001244syslogin_perform_login(struct logininfo *li)
1245{
andre2ff7b5d2000-06-03 14:57:40 +00001246 struct utmp *ut;
1247
1248 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) {
1249 log("syslogin_perform_login: couldn't malloc()");
1250 return 0;
1251 }
1252 construct_utmp(li, ut);
1253 login(ut);
1254
1255 return 1;
andre61e67252000-06-04 17:07:49 +00001256}
1257
andre2ff7b5d2000-06-03 14:57:40 +00001258static int
andre61e67252000-06-04 17:07:49 +00001259syslogin_perform_logout(struct logininfo *li)
1260{
Damien Millerdd47aa22000-06-27 11:18:27 +10001261# ifdef HAVE_LOGOUT
andre2ff7b5d2000-06-03 14:57:40 +00001262 char line[8];
1263
1264 (void)line_stripname(line, li->line, sizeof(line));
1265
1266 if (!logout(line)) {
1267 log("syslogin_perform_logout: logout() returned an error");
Damien Millerdd47aa22000-06-27 11:18:27 +10001268# ifdef HAVE_LOGWTMP
andre2ff7b5d2000-06-03 14:57:40 +00001269 } else {
1270 logwtmp(line, "", "");
1271 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001272# endif
andre6bb92372000-06-19 08:20:03 +00001273 /* FIXME: (ATL - if the need arises) What to do if we have
1274 * login, but no logout? what if logout but no logwtmp? All
1275 * routines are in libutil so they should all be there,
1276 * but... */
Damien Millerdd47aa22000-06-27 11:18:27 +10001277# endif
andre2ff7b5d2000-06-03 14:57:40 +00001278 return 1;
andre61e67252000-06-04 17:07:49 +00001279}
andre2ff7b5d2000-06-03 14:57:40 +00001280
andre2ff7b5d2000-06-03 14:57:40 +00001281int
andre61e67252000-06-04 17:07:49 +00001282syslogin_write_entry(struct logininfo *li)
1283{
andre2ff7b5d2000-06-03 14:57:40 +00001284 switch (li->type) {
1285 case LTYPE_LOGIN:
1286 return syslogin_perform_login(li);
1287 case LTYPE_LOGOUT:
1288 return syslogin_perform_logout(li);
1289 default:
1290 log("syslogin_write_entry: Invalid type field");
1291 return 0;
1292 }
andre61e67252000-06-04 17:07:49 +00001293}
Damien Millerd5bf3072000-06-07 21:32:13 +10001294#endif /* USE_LOGIN */
andre2ff7b5d2000-06-03 14:57:40 +00001295
1296/* end of file log-syslogin.c */
1297
andre2ff7b5d2000-06-03 14:57:40 +00001298/**
andre61e67252000-06-04 17:07:49 +00001299 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001300 **/
1301
1302#ifdef USE_LASTLOG
Damien Millerdd47aa22000-06-27 11:18:27 +10001303#define LL_FILE 1
1304#define LL_DIR 2
1305#define LL_OTHER 3
andre2ff7b5d2000-06-03 14:57:40 +00001306
andre2ff7b5d2000-06-03 14:57:40 +00001307static void
andre61e67252000-06-04 17:07:49 +00001308lastlog_construct(struct logininfo *li, struct lastlog *last)
1309{
andre2ff7b5d2000-06-03 14:57:40 +00001310 /* clear the structure */
1311 memset(last, '\0', sizeof(struct lastlog));
1312
Damien Millerdd47aa22000-06-27 11:18:27 +10001313 (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
andre6bb92372000-06-19 08:20:03 +00001314 strlcpy(last->ll_host, li->hostname,
1315 MIN_SIZEOF(last->ll_host, li->hostname));
andre2ff7b5d2000-06-03 14:57:40 +00001316 last->ll_time = li->tv_sec;
andre61e67252000-06-04 17:07:49 +00001317}
andre2ff7b5d2000-06-03 14:57:40 +00001318
andre2ff7b5d2000-06-03 14:57:40 +00001319static int
andre61e67252000-06-04 17:07:49 +00001320lastlog_filetype(char *filename)
1321{
andre2ff7b5d2000-06-03 14:57:40 +00001322 struct stat st;
1323
Damien Millerdd47aa22000-06-27 11:18:27 +10001324 if (stat(LASTLOG_FILE, &st) != 0) {
1325 log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
1326 strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +00001327 return 0;
1328 }
andre2ff7b5d2000-06-03 14:57:40 +00001329 if (S_ISDIR(st.st_mode))
1330 return LL_DIR;
1331 else if (S_ISREG(st.st_mode))
1332 return LL_FILE;
1333 else
1334 return LL_OTHER;
andre61e67252000-06-04 17:07:49 +00001335}
andre2ff7b5d2000-06-03 14:57:40 +00001336
1337
1338/* open the file (using filemode) and seek to the login entry */
1339static int
andre61e67252000-06-04 17:07:49 +00001340lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1341{
andre2ff7b5d2000-06-03 14:57:40 +00001342 off_t offset;
1343 int type;
1344 char lastlog_file[1024];
1345
1346 type = lastlog_filetype(LASTLOG_FILE);
1347 switch (type) {
Damien Millerf8af08d2000-06-27 09:40:06 +10001348 case LL_FILE:
1349 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1350 break;
1351 case LL_DIR:
1352 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1353 LASTLOG_FILE, li->username);
1354 break;
1355 default:
1356 log("lastlog_openseek: %.100s is not a file or directory!",
1357 LASTLOG_FILE);
1358 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001359 }
andre2ff7b5d2000-06-03 14:57:40 +00001360
1361 *fd = open(lastlog_file, filemode);
1362 if ( *fd < 0) {
1363 log("lastlog_openseek: Couldn't open %s: %s",
1364 lastlog_file, strerror(errno));
1365 return 0;
1366 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001367
andre2ff7b5d2000-06-03 14:57:40 +00001368 /* find this uid's offset in the lastlog file */
1369 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
1370
1371 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1372 log("lastlog_openseek: %s->lseek(): %s",
1373 lastlog_file, strerror(errno));
1374 return 0;
1375 }
1376 return 1;
andre61e67252000-06-04 17:07:49 +00001377}
andre2ff7b5d2000-06-03 14:57:40 +00001378
1379static int
andre61e67252000-06-04 17:07:49 +00001380lastlog_perform_login(struct logininfo *li)
1381{
andre2ff7b5d2000-06-03 14:57:40 +00001382 struct lastlog last;
1383 int fd;
1384
1385 /* create our struct lastlog */
1386 lastlog_construct(li, &last);
1387
1388 /* write the entry */
1389 if (lastlog_openseek(li, &fd, O_RDWR)) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001390 if (write(fd, &last, sizeof(struct lastlog)) !=
1391 sizeof(struct lastlog)) {
andre2ff7b5d2000-06-03 14:57:40 +00001392 log("lastlog_write_filemode: Error writing to %s: %s",
1393 LASTLOG_FILE, strerror(errno));
1394 return 0;
1395 }
1396 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001397 } else {
andre2ff7b5d2000-06-03 14:57:40 +00001398 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001399 }
andre61e67252000-06-04 17:07:49 +00001400}
andre2ff7b5d2000-06-03 14:57:40 +00001401
andre2ff7b5d2000-06-03 14:57:40 +00001402int
andre61e67252000-06-04 17:07:49 +00001403lastlog_write_entry(struct logininfo *li)
1404{
andre2ff7b5d2000-06-03 14:57:40 +00001405 switch(li->type) {
1406 case LTYPE_LOGIN:
1407 return lastlog_perform_login(li);
1408 default:
1409 log("lastlog_write_entry: Invalid type field");
1410 return 0;
1411 }
andre61e67252000-06-04 17:07:49 +00001412}
andre2ff7b5d2000-06-03 14:57:40 +00001413
andre2ff7b5d2000-06-03 14:57:40 +00001414static void
andre61e67252000-06-04 17:07:49 +00001415lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1416{
andre2ff7b5d2000-06-03 14:57:40 +00001417 line_fullname(li->line, last->ll_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001418 strlcpy(li->hostname, last->ll_host,
andre6bb92372000-06-19 08:20:03 +00001419 MIN_SIZEOF(li->hostname, last->ll_host));
andre2ff7b5d2000-06-03 14:57:40 +00001420 li->tv_sec = last->ll_time;
andre61e67252000-06-04 17:07:49 +00001421}
andre2ff7b5d2000-06-03 14:57:40 +00001422
andre2ff7b5d2000-06-03 14:57:40 +00001423int
andre61e67252000-06-04 17:07:49 +00001424lastlog_get_entry(struct logininfo *li)
1425{
andre2ff7b5d2000-06-03 14:57:40 +00001426 struct lastlog last;
1427 int fd;
1428
1429 if (lastlog_openseek(li, &fd, O_RDONLY)) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001430 if ( read(fd, &last, sizeof(struct lastlog)) !=
1431 sizeof(struct lastlog) ) {
andre2ff7b5d2000-06-03 14:57:40 +00001432 log("lastlog_write_filemode: Error reading from %s: %s",
1433 LASTLOG_FILE, strerror(errno));
1434 return 0;
1435 } else {
1436 lastlog_populate_entry(li, &last);
1437 return 1;
1438 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001439 } else {
andre2ff7b5d2000-06-03 14:57:40 +00001440 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001441 }
andre61e67252000-06-04 17:07:49 +00001442}
Damien Millerd5bf3072000-06-07 21:32:13 +10001443#endif /* USE_LASTLOG */