blob: 8b82fa29d353c933d87af95640dcb4d8d11f4185 [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 Miller7a0e5dc2000-07-11 12:15:54 +1000163RCSID("$Id: loginrec.c,v 1.17 2000/07/11 02:15:54 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
andre61e67252000-06-04 17:07:49 +0000276 memset(li, '\0', sizeof(struct logininfo));
277 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
314 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo));
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
andre2ff7b5d2000-06-03 14:57:40 +0000342 memset(li, 0, sizeof(struct logininfo));
343
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{
andre2ff7b5d2000-06-03 14:57:40 +0000572 memset(ut, '\0', sizeof(struct utmp));
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{
646 memset(utx, '\0', sizeof(struct utmpx));
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 */
andre2ff7b5d2000-06-03 14:57:40 +0000726 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
727
728 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
729 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
730 /*
731 * Prevent luser from zero'ing out ut_host.
732 * If the new ut_line is empty but the old one is not
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000733 * and ut_line and ut_name match, preserve the old ut_line.
andre2ff7b5d2000-06-03 14:57:40 +0000734 */
Damien Miller53c5d462000-06-28 00:50:50 +1000735 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
736 (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
737 (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000738 (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
andre2ff7b5d2000-06-03 14:57:40 +0000739 (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
Damien Miller53c5d462000-06-28 00:50:50 +1000740 }
741
andre2ff7b5d2000-06-03 14:57:40 +0000742 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
Damien Miller53c5d462000-06-28 00:50:50 +1000743 if (atomicio(write, fd, ut, sizeof(ut)) != sizeof(ut))
andre2ff7b5d2000-06-03 14:57:40 +0000744 log("utmp_write_direct: error writing %s: %s",
andre6bb92372000-06-19 08:20:03 +0000745 UTMP_FILE, strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +0000746
747 (void)close(fd);
748 return 1;
Damien Miller53c5d462000-06-28 00:50:50 +1000749 } else {
andre2ff7b5d2000-06-03 14:57:40 +0000750 return 0;
Damien Miller53c5d462000-06-28 00:50:50 +1000751 }
andre61e67252000-06-04 17:07:49 +0000752}
Damien Millerdd47aa22000-06-27 11:18:27 +1000753# endif /* UTMP_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000754
755static int
andre61e67252000-06-04 17:07:49 +0000756utmp_perform_login(struct logininfo *li)
757{
andre2ff7b5d2000-06-03 14:57:40 +0000758 struct utmp ut;
759
760 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000761# ifdef UTMP_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000762 if (!utmp_write_library(li, &ut)) {
andre6bb92372000-06-19 08:20:03 +0000763 log("utmp_perform_login: utmp_write_library() failed");
andre2ff7b5d2000-06-03 14:57:40 +0000764 return 0;
765 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000766# else
andre2ff7b5d2000-06-03 14:57:40 +0000767 if (!utmp_write_direct(li, &ut)) {
768 log("utmp_perform_login: utmp_write_direct() failed");
769 return 0;
770 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000771# endif
andre2ff7b5d2000-06-03 14:57:40 +0000772 return 1;
andre61e67252000-06-04 17:07:49 +0000773}
andre2ff7b5d2000-06-03 14:57:40 +0000774
775
776static int
andre61e67252000-06-04 17:07:49 +0000777utmp_perform_logout(struct logininfo *li)
778{
andre2ff7b5d2000-06-03 14:57:40 +0000779 struct utmp ut;
780
andre6bb92372000-06-19 08:20:03 +0000781 construct_utmp(li, &ut);
Damien Millerdd47aa22000-06-27 11:18:27 +1000782# ifdef UTMP_USE_LIBRARY
andre6bb92372000-06-19 08:20:03 +0000783 if (!utmp_write_library(li, &ut)) {
784 log("utmp_perform_logout: utmp_write_library() failed");
785 return 0;
786 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000787# else
andre6bb92372000-06-19 08:20:03 +0000788 if (!utmp_write_direct(li, &ut)) {
789 log("utmp_perform_logout: utmp_write_direct() failed");
790 return 0;
791 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000792# endif
andre2ff7b5d2000-06-03 14:57:40 +0000793 return 1;
andre61e67252000-06-04 17:07:49 +0000794}
andre2ff7b5d2000-06-03 14:57:40 +0000795
796
797int
andre61e67252000-06-04 17:07:49 +0000798utmp_write_entry(struct logininfo *li)
799{
andre2ff7b5d2000-06-03 14:57:40 +0000800 switch(li->type) {
801 case LTYPE_LOGIN:
802 return utmp_perform_login(li);
803
804 case LTYPE_LOGOUT:
805 return utmp_perform_logout(li);
806
807 default:
808 log("utmp_write_entry: invalid type field");
809 return 0;
810 }
andre61e67252000-06-04 17:07:49 +0000811}
Damien Millerdd47aa22000-06-27 11:18:27 +1000812#endif /* USE_UTMP */
andre2ff7b5d2000-06-03 14:57:40 +0000813
814
815/**
andre61e67252000-06-04 17:07:49 +0000816 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000817 **/
818
819/* not much point if we don't want utmpx entries */
820#ifdef USE_UTMPX
821
andre2ff7b5d2000-06-03 14:57:40 +0000822/* if we have the wherewithall, use pututxline etc. */
Damien Millerdd47aa22000-06-27 11:18:27 +1000823# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
824 defined(HAVE_PUTUTXLINE)
andre2ff7b5d2000-06-03 14:57:40 +0000825# define UTMPX_USE_LIBRARY
Damien Millerdd47aa22000-06-27 11:18:27 +1000826# endif
andre2ff7b5d2000-06-03 14:57:40 +0000827
828
829/* write a utmpx entry with the system's help (pututxline() and pals) */
Damien Millerdd47aa22000-06-27 11:18:27 +1000830# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000831static int
andre61e67252000-06-04 17:07:49 +0000832utmpx_write_library(struct logininfo *li, struct utmpx *utx)
833{
andre2ff7b5d2000-06-03 14:57:40 +0000834 setutxent();
835 pututxline(utx);
836
Damien Millerdd47aa22000-06-27 11:18:27 +1000837# ifdef HAVE_ENDUTXENT
andre2ff7b5d2000-06-03 14:57:40 +0000838 endutxent();
Damien Millerdd47aa22000-06-27 11:18:27 +1000839# endif
andre2ff7b5d2000-06-03 14:57:40 +0000840 return 1;
andre61e67252000-06-04 17:07:49 +0000841}
andre2ff7b5d2000-06-03 14:57:40 +0000842
Damien Millerdd47aa22000-06-27 11:18:27 +1000843# else /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000844
845/* write a utmp entry direct to the file */
846static int
andre61e67252000-06-04 17:07:49 +0000847utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
848{
andre2ff7b5d2000-06-03 14:57:40 +0000849 log("utmpx_write_direct: not implemented!");
850 return 0;
andre61e67252000-06-04 17:07:49 +0000851}
Damien Millerdd47aa22000-06-27 11:18:27 +1000852# endif /* UTMPX_USE_LIBRARY */
andre2ff7b5d2000-06-03 14:57:40 +0000853
854static int
andre61e67252000-06-04 17:07:49 +0000855utmpx_perform_login(struct logininfo *li)
856{
andre2ff7b5d2000-06-03 14:57:40 +0000857 struct utmpx utx;
858
859 construct_utmpx(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000860# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000861 if (!utmpx_write_library(li, &utx)) {
862 log("utmpx_perform_login: utmp_write_library() failed");
863 return 0;
864 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000865# else
andre2ff7b5d2000-06-03 14:57:40 +0000866 if (!utmpx_write_direct(li, &ut)) {
867 log("utmpx_perform_login: utmp_write_direct() failed");
868 return 0;
869 }
Damien Millerdd47aa22000-06-27 11:18:27 +1000870# endif
andre2ff7b5d2000-06-03 14:57:40 +0000871 return 1;
andre61e67252000-06-04 17:07:49 +0000872}
andre2ff7b5d2000-06-03 14:57:40 +0000873
874
875static int
andre61e67252000-06-04 17:07:49 +0000876utmpx_perform_logout(struct logininfo *li)
877{
andre2ff7b5d2000-06-03 14:57:40 +0000878 struct utmpx utx;
879
880 memset(&utx, '\0', sizeof(utx));
881 set_utmpx_time(li, &utx);
882 line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +1000883# ifdef HAVE_ID_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000884 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
Damien Millerdd47aa22000-06-27 11:18:27 +1000885# endif
886# ifdef HAVE_TYPE_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +0000887 utx.ut_type = DEAD_PROCESS;
Damien Millerdd47aa22000-06-27 11:18:27 +1000888# endif
andre2ff7b5d2000-06-03 14:57:40 +0000889
Damien Millerdd47aa22000-06-27 11:18:27 +1000890# ifdef UTMPX_USE_LIBRARY
andre2ff7b5d2000-06-03 14:57:40 +0000891 utmpx_write_library(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000892# else
andre2ff7b5d2000-06-03 14:57:40 +0000893 utmpx_write_direct(li, &utx);
Damien Millerdd47aa22000-06-27 11:18:27 +1000894# endif
andre2ff7b5d2000-06-03 14:57:40 +0000895 return 1;
andre61e67252000-06-04 17:07:49 +0000896}
andre2ff7b5d2000-06-03 14:57:40 +0000897
andre2ff7b5d2000-06-03 14:57:40 +0000898int
andre61e67252000-06-04 17:07:49 +0000899utmpx_write_entry(struct logininfo *li)
900{
andre2ff7b5d2000-06-03 14:57:40 +0000901 switch(li->type) {
902 case LTYPE_LOGIN:
903 return utmpx_perform_login(li);
904 case LTYPE_LOGOUT:
905 return utmpx_perform_logout(li);
906 default:
907 log("utmpx_write_entry: invalid type field");
908 return 0;
909 }
andre61e67252000-06-04 17:07:49 +0000910}
Damien Millerdd47aa22000-06-27 11:18:27 +1000911#endif /* USE_UTMPX */
andre2ff7b5d2000-06-03 14:57:40 +0000912
913
914/**
andre61e67252000-06-04 17:07:49 +0000915 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000916 **/
917
918#ifdef USE_WTMP
919
andre2ff7b5d2000-06-03 14:57:40 +0000920/* write a wtmp entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000921/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000922static int
andre61e67252000-06-04 17:07:49 +0000923wtmp_write(struct logininfo *li, struct utmp *ut)
924{
andre2ff7b5d2000-06-03 14:57:40 +0000925 struct stat buf;
926 int fd, ret = 1;
927
928 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
929 log("wtmp_write: problem writing %s: %s",
930 WTMP_FILE, strerror(errno));
931 return 0;
932 }
andre61e67252000-06-04 17:07:49 +0000933 if (fstat(fd, &buf) == 0)
Damien Miller53c5d462000-06-28 00:50:50 +1000934 if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
andre2ff7b5d2000-06-03 14:57:40 +0000935 ftruncate(fd, buf.st_size);
936 log("wtmp_write: problem writing %s: %s",
937 WTMP_FILE, strerror(errno));
938 ret = 0;
939 }
940 (void)close(fd);
andre2ff7b5d2000-06-03 14:57:40 +0000941 return ret;
andre61e67252000-06-04 17:07:49 +0000942}
andre2ff7b5d2000-06-03 14:57:40 +0000943
andre2ff7b5d2000-06-03 14:57:40 +0000944static int
Damien Millerdd47aa22000-06-27 11:18:27 +1000945wtmp_perform_login(struct logininfo *li)
946{
andre2ff7b5d2000-06-03 14:57:40 +0000947 struct utmp ut;
948
949 construct_utmp(li, &ut);
950 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000951}
andre2ff7b5d2000-06-03 14:57:40 +0000952
953
954static int
andre61e67252000-06-04 17:07:49 +0000955wtmp_perform_logout(struct logininfo *li)
956{
andre2ff7b5d2000-06-03 14:57:40 +0000957 struct utmp ut;
958
959 construct_utmp(li, &ut);
andre2ff7b5d2000-06-03 14:57:40 +0000960 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000961}
andre2ff7b5d2000-06-03 14:57:40 +0000962
963
964int
andre61e67252000-06-04 17:07:49 +0000965wtmp_write_entry(struct logininfo *li)
966{
andre2ff7b5d2000-06-03 14:57:40 +0000967 switch(li->type) {
968 case LTYPE_LOGIN:
969 return wtmp_perform_login(li);
970 case LTYPE_LOGOUT:
971 return wtmp_perform_logout(li);
972 default:
973 log("wtmp_write_entry: invalid type field");
974 return 0;
975 }
andre61e67252000-06-04 17:07:49 +0000976}
andre2ff7b5d2000-06-03 14:57:40 +0000977
978
andre6bb92372000-06-19 08:20:03 +0000979/* Notes on fetching login data from wtmp/wtmpx
980 *
981 * Logouts are usually recorded with (amongst other things) a blank
982 * username on a given tty line. However, some systems (HP-UX is one)
983 * leave all fields set, but change the ut_type field to DEAD_PROCESS.
984 *
985 * Since we're only looking for logins here, we know that the username
986 * must be set correctly. On systems that leave it in, we check for
987 * ut_type==USER_PROCESS (indicating a login.)
988 *
989 * Portability: Some systems may set something other than USER_PROCESS
990 * to indicate a login process. I don't know of any as I write. Also,
991 * it's possible that some systems may both leave the username in
992 * place and not have ut_type.
993 */
994
andre6bb92372000-06-19 08:20:03 +0000995/* return true if this wtmp entry indicates a login */
996static int
997wtmp_islogin(struct logininfo *li, struct utmp *ut)
998{
Damien Miller7a0e5dc2000-07-11 12:15:54 +1000999 if (strncmp(li->username, ut->ut_name,
1000 MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001001# ifdef HAVE_TYPE_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001002 if (ut->ut_type & USER_PROCESS)
1003 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001004# else
andre6bb92372000-06-19 08:20:03 +00001005 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001006# endif
andre6bb92372000-06-19 08:20:03 +00001007 }
1008 return 0;
1009}
1010
andre2ff7b5d2000-06-03 14:57:40 +00001011int
andre61e67252000-06-04 17:07:49 +00001012wtmp_get_entry(struct logininfo *li)
1013{
andre2ff7b5d2000-06-03 14:57:40 +00001014 struct stat st;
1015 struct utmp ut;
andre6bb92372000-06-19 08:20:03 +00001016 int fd, found=0;
1017
1018 /* Clear the time entries in our logininfo */
1019 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001020
1021 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1022 log("wtmp_get_entry: problem opening %s: %s",
1023 WTMP_FILE, strerror(errno));
1024 return 0;
1025 }
andre61e67252000-06-04 17:07:49 +00001026 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001027 log("wtmp_get_entry: couldn't stat %s: %s",
1028 WTMP_FILE, strerror(errno));
1029 close(fd);
1030 return 0;
1031 }
andre2ff7b5d2000-06-03 14:57:40 +00001032
andre6bb92372000-06-19 08:20:03 +00001033 /* Seek to the start of the last struct utmp */
1034 if (lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END) == -1) {
1035 /* Looks like we've got a fresh wtmp file */
1036 close(fd);
1037 return 0;
1038 }
1039
1040 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001041 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
andre2ff7b5d2000-06-03 14:57:40 +00001042 log("wtmp_get_entry: read of %s failed: %s",
1043 WTMP_FILE, strerror(errno));
1044 close (fd);
1045 return 0;
1046 }
andre6bb92372000-06-19 08:20:03 +00001047 if ( wtmp_islogin(li, &ut) ) {
1048 found = 1;
1049 /* We've already checked for a time in struct
1050 * utmp, in login_getlast(). */
Damien Millerdd47aa22000-06-27 11:18:27 +10001051# ifdef HAVE_TIME_IN_UTMP
andre2ff7b5d2000-06-03 14:57:40 +00001052 li->tv_sec = ut.ut_time;
Damien Millerdd47aa22000-06-27 11:18:27 +10001053# else
andre2ff7b5d2000-06-03 14:57:40 +00001054# if HAVE_TV_IN_UTMP
1055 li->tv_sec = ut.ut_tv.tv_sec;
1056# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001057# endif
andre6bb92372000-06-19 08:20:03 +00001058 line_fullname(li->line, ut.ut_line,
1059 MIN_SIZEOF(li->line, ut.ut_line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001060# ifdef HAVE_HOST_IN_UTMP
andre6bb92372000-06-19 08:20:03 +00001061 strlcpy(li->hostname, ut.ut_host,
1062 MIN_SIZEOF(li->hostname, ut.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001063# endif
andre6bb92372000-06-19 08:20:03 +00001064 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001065 }
andre6bb92372000-06-19 08:20:03 +00001066 /* Seek back 2 x struct utmp */
andre2ff7b5d2000-06-03 14:57:40 +00001067 if (lseek(fd, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1) {
andre6bb92372000-06-19 08:20:03 +00001068 /* We've found the start of the file, so quit */
andre2ff7b5d2000-06-03 14:57:40 +00001069 close (fd);
1070 return 0;
1071 }
andre6bb92372000-06-19 08:20:03 +00001072 }
1073
1074 /* We found an entry. Tidy up and return */
1075 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001076 return 1;
andre61e67252000-06-04 17:07:49 +00001077}
Damien Millerdd47aa22000-06-27 11:18:27 +10001078# endif /* USE_WTMP */
andre2ff7b5d2000-06-03 14:57:40 +00001079
1080
1081/**
andre61e67252000-06-04 17:07:49 +00001082 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +00001083 **/
1084
1085#ifdef USE_WTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001086/* write a wtmpx entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +00001087/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +00001088static int
andre61e67252000-06-04 17:07:49 +00001089wtmpx_write(struct logininfo *li, struct utmpx *utx)
1090{
andre2ff7b5d2000-06-03 14:57:40 +00001091 struct stat buf;
1092 int fd, ret = 1;
1093
1094 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1095 log("wtmpx_write: problem opening %s: %s",
1096 WTMPX_FILE, strerror(errno));
1097 return 0;
1098 }
1099
1100 if (fstat(fd, &buf) == 0)
Damien Miller53c5d462000-06-28 00:50:50 +10001101 if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
andre2ff7b5d2000-06-03 14:57:40 +00001102 ftruncate(fd, buf.st_size);
1103 log("wtmpx_write: problem writing %s: %s",
1104 WTMPX_FILE, strerror(errno));
1105 ret = 0;
1106 }
1107 (void)close(fd);
1108
1109 return ret;
andre61e67252000-06-04 17:07:49 +00001110}
andre2ff7b5d2000-06-03 14:57:40 +00001111
1112
1113static int
andre61e67252000-06-04 17:07:49 +00001114wtmpx_perform_login(struct logininfo *li)
1115{
andre2ff7b5d2000-06-03 14:57:40 +00001116 struct utmpx utx;
1117
1118 construct_utmpx(li, &utx);
1119 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001120}
andre2ff7b5d2000-06-03 14:57:40 +00001121
1122
1123static int
andre61e67252000-06-04 17:07:49 +00001124wtmpx_perform_logout(struct logininfo *li)
1125{
andre2ff7b5d2000-06-03 14:57:40 +00001126 struct utmpx utx;
1127
1128 construct_utmpx(li, &utx);
andre2ff7b5d2000-06-03 14:57:40 +00001129 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001130}
andre2ff7b5d2000-06-03 14:57:40 +00001131
1132
1133int
andre61e67252000-06-04 17:07:49 +00001134wtmpx_write_entry(struct logininfo *li)
1135{
andre2ff7b5d2000-06-03 14:57:40 +00001136 switch(li->type) {
1137 case LTYPE_LOGIN:
1138 return wtmpx_perform_login(li);
1139 case LTYPE_LOGOUT:
1140 return wtmpx_perform_logout(li);
1141 default:
1142 log("wtmpx_write_entry: invalid type field");
1143 return 0;
1144 }
andre61e67252000-06-04 17:07:49 +00001145}
andre2ff7b5d2000-06-03 14:57:40 +00001146
andre6bb92372000-06-19 08:20:03 +00001147/* Please see the notes above wtmp_islogin() for information about the
1148 next two functions */
1149
1150/* Return true if this wtmpx entry indicates a login */
1151static int
1152wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1153{
Damien Miller7a0e5dc2000-07-11 12:15:54 +10001154 if ( strncmp(li->username, utx->ut_name,
1155 MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001156# ifdef HAVE_TYPE_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001157 if (utx->ut_type == USER_PROCESS)
1158 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001159# else
andre6bb92372000-06-19 08:20:03 +00001160 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001161# endif
andre6bb92372000-06-19 08:20:03 +00001162 }
1163 return 0;
1164}
1165
andre2ff7b5d2000-06-03 14:57:40 +00001166
1167int
andre61e67252000-06-04 17:07:49 +00001168wtmpx_get_entry(struct logininfo *li)
1169{
andre2ff7b5d2000-06-03 14:57:40 +00001170 struct stat st;
1171 struct utmpx utx;
andre6bb92372000-06-19 08:20:03 +00001172 int fd, found=0;
1173
1174 /* Clear the time entries */
1175 li->tv_sec = li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +00001176
1177 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1178 log("wtmpx_get_entry: problem opening %s: %s",
1179 WTMPX_FILE, strerror(errno));
1180 return 0;
1181 }
andre61e67252000-06-04 17:07:49 +00001182 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001183 log("wtmpx_get_entry: couldn't stat %s: %s",
1184 WTMP_FILE, strerror(errno));
1185 close(fd);
1186 return 0;
1187 }
andre6bb92372000-06-19 08:20:03 +00001188
1189 /* Seek to the start of the last struct utmpx */
1190 if (lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END) == -1 ) {
1191 /* probably a newly rotated wtmpx file */
1192 close(fd);
1193 return 0;
1194 }
andre2ff7b5d2000-06-03 14:57:40 +00001195
andre6bb92372000-06-19 08:20:03 +00001196 while (!found) {
Damien Miller53c5d462000-06-28 00:50:50 +10001197 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
andre2ff7b5d2000-06-03 14:57:40 +00001198 log("wtmpx_get_entry: read of %s failed: %s",
1199 WTMPX_FILE, strerror(errno));
1200 close (fd);
1201 return 0;
1202 }
andre2ff7b5d2000-06-03 14:57:40 +00001203 /* Logouts are recorded as a blank username on a particular line.
1204 * So, we just need to find the username in struct utmpx */
andre6bb92372000-06-19 08:20:03 +00001205 if ( wtmpx_islogin(li, &utx) ) {
Damien Millerdd47aa22000-06-27 11:18:27 +10001206# ifdef HAVE_TV_IN_UTMPX
andre2ff7b5d2000-06-03 14:57:40 +00001207 li->tv_sec = utx.ut_tv.tv_sec;
Damien Millerdd47aa22000-06-27 11:18:27 +10001208# else
andre2ff7b5d2000-06-03 14:57:40 +00001209# ifdef HAVE_TIME_IN_UTMPX
1210 li->tv_sec = utx.ut_time;
1211# endif
Damien Millerdd47aa22000-06-27 11:18:27 +10001212# endif
Damien Miller1a132252000-06-13 21:23:17 +10001213 line_fullname(li->line, utx.ut_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001214# ifdef HAVE_HOST_IN_UTMPX
andre6bb92372000-06-19 08:20:03 +00001215 strlcpy(li->hostname, utx.ut_host,
1216 MIN_SIZEOF(li->hostname, utx.ut_host));
Damien Millerdd47aa22000-06-27 11:18:27 +10001217# endif
andre6bb92372000-06-19 08:20:03 +00001218 continue;
andre2ff7b5d2000-06-03 14:57:40 +00001219 }
1220 if (lseek(fd, (off_t)(0-2*sizeof(struct utmpx)), SEEK_CUR) == -1) {
1221 close (fd);
1222 return 0;
1223 }
andre6bb92372000-06-19 08:20:03 +00001224 }
1225
1226 close(fd);
andre2ff7b5d2000-06-03 14:57:40 +00001227 return 1;
andre61e67252000-06-04 17:07:49 +00001228}
Damien Millerd5bf3072000-06-07 21:32:13 +10001229#endif /* USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001230
andre2ff7b5d2000-06-03 14:57:40 +00001231/**
andre61e67252000-06-04 17:07:49 +00001232 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001233 **/
1234
1235#ifdef USE_LOGIN
andre2ff7b5d2000-06-03 14:57:40 +00001236static int
andre61e67252000-06-04 17:07:49 +00001237syslogin_perform_login(struct logininfo *li)
1238{
andre2ff7b5d2000-06-03 14:57:40 +00001239 struct utmp *ut;
1240
1241 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) {
1242 log("syslogin_perform_login: couldn't malloc()");
1243 return 0;
1244 }
1245 construct_utmp(li, ut);
1246 login(ut);
1247
1248 return 1;
andre61e67252000-06-04 17:07:49 +00001249}
1250
andre2ff7b5d2000-06-03 14:57:40 +00001251static int
andre61e67252000-06-04 17:07:49 +00001252syslogin_perform_logout(struct logininfo *li)
1253{
Damien Millerdd47aa22000-06-27 11:18:27 +10001254# ifdef HAVE_LOGOUT
andre2ff7b5d2000-06-03 14:57:40 +00001255 char line[8];
1256
1257 (void)line_stripname(line, li->line, sizeof(line));
1258
1259 if (!logout(line)) {
1260 log("syslogin_perform_logout: logout() returned an error");
Damien Millerdd47aa22000-06-27 11:18:27 +10001261# ifdef HAVE_LOGWTMP
andre2ff7b5d2000-06-03 14:57:40 +00001262 } else {
1263 logwtmp(line, "", "");
Damien Millerdd47aa22000-06-27 11:18:27 +10001264# endif
Damien Miller9b6d4ab2000-07-02 08:43:18 +10001265 }
andre6bb92372000-06-19 08:20:03 +00001266 /* FIXME: (ATL - if the need arises) What to do if we have
1267 * login, but no logout? what if logout but no logwtmp? All
1268 * routines are in libutil so they should all be there,
1269 * but... */
Damien Millerdd47aa22000-06-27 11:18:27 +10001270# endif
andre2ff7b5d2000-06-03 14:57:40 +00001271 return 1;
andre61e67252000-06-04 17:07:49 +00001272}
andre2ff7b5d2000-06-03 14:57:40 +00001273
andre2ff7b5d2000-06-03 14:57:40 +00001274int
andre61e67252000-06-04 17:07:49 +00001275syslogin_write_entry(struct logininfo *li)
1276{
andre2ff7b5d2000-06-03 14:57:40 +00001277 switch (li->type) {
1278 case LTYPE_LOGIN:
1279 return syslogin_perform_login(li);
1280 case LTYPE_LOGOUT:
1281 return syslogin_perform_logout(li);
1282 default:
1283 log("syslogin_write_entry: Invalid type field");
1284 return 0;
1285 }
andre61e67252000-06-04 17:07:49 +00001286}
Damien Millerd5bf3072000-06-07 21:32:13 +10001287#endif /* USE_LOGIN */
andre2ff7b5d2000-06-03 14:57:40 +00001288
1289/* end of file log-syslogin.c */
1290
andre2ff7b5d2000-06-03 14:57:40 +00001291/**
andre61e67252000-06-04 17:07:49 +00001292 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001293 **/
1294
1295#ifdef USE_LASTLOG
Damien Millerdd47aa22000-06-27 11:18:27 +10001296#define LL_FILE 1
1297#define LL_DIR 2
1298#define LL_OTHER 3
andre2ff7b5d2000-06-03 14:57:40 +00001299
andre2ff7b5d2000-06-03 14:57:40 +00001300static void
andre61e67252000-06-04 17:07:49 +00001301lastlog_construct(struct logininfo *li, struct lastlog *last)
1302{
andre2ff7b5d2000-06-03 14:57:40 +00001303 /* clear the structure */
1304 memset(last, '\0', sizeof(struct lastlog));
1305
Damien Millerdd47aa22000-06-27 11:18:27 +10001306 (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
andre6bb92372000-06-19 08:20:03 +00001307 strlcpy(last->ll_host, li->hostname,
1308 MIN_SIZEOF(last->ll_host, li->hostname));
andre2ff7b5d2000-06-03 14:57:40 +00001309 last->ll_time = li->tv_sec;
andre61e67252000-06-04 17:07:49 +00001310}
andre2ff7b5d2000-06-03 14:57:40 +00001311
andre2ff7b5d2000-06-03 14:57:40 +00001312static int
andre61e67252000-06-04 17:07:49 +00001313lastlog_filetype(char *filename)
1314{
andre2ff7b5d2000-06-03 14:57:40 +00001315 struct stat st;
1316
Damien Millerdd47aa22000-06-27 11:18:27 +10001317 if (stat(LASTLOG_FILE, &st) != 0) {
1318 log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
1319 strerror(errno));
andre2ff7b5d2000-06-03 14:57:40 +00001320 return 0;
1321 }
andre2ff7b5d2000-06-03 14:57:40 +00001322 if (S_ISDIR(st.st_mode))
1323 return LL_DIR;
1324 else if (S_ISREG(st.st_mode))
1325 return LL_FILE;
1326 else
1327 return LL_OTHER;
andre61e67252000-06-04 17:07:49 +00001328}
andre2ff7b5d2000-06-03 14:57:40 +00001329
1330
1331/* open the file (using filemode) and seek to the login entry */
1332static int
andre61e67252000-06-04 17:07:49 +00001333lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1334{
andre2ff7b5d2000-06-03 14:57:40 +00001335 off_t offset;
1336 int type;
1337 char lastlog_file[1024];
1338
1339 type = lastlog_filetype(LASTLOG_FILE);
1340 switch (type) {
Damien Millerf8af08d2000-06-27 09:40:06 +10001341 case LL_FILE:
1342 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1343 break;
1344 case LL_DIR:
1345 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1346 LASTLOG_FILE, li->username);
1347 break;
1348 default:
1349 log("lastlog_openseek: %.100s is not a file or directory!",
1350 LASTLOG_FILE);
1351 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001352 }
andre2ff7b5d2000-06-03 14:57:40 +00001353
1354 *fd = open(lastlog_file, filemode);
1355 if ( *fd < 0) {
Damien Miller53c5d462000-06-28 00:50:50 +10001356 debug("lastlog_openseek: Couldn't open %s: %s",
andre2ff7b5d2000-06-03 14:57:40 +00001357 lastlog_file, strerror(errno));
1358 return 0;
1359 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001360
andre2ff7b5d2000-06-03 14:57:40 +00001361 /* find this uid's offset in the lastlog file */
1362 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
1363
1364 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1365 log("lastlog_openseek: %s->lseek(): %s",
1366 lastlog_file, strerror(errno));
1367 return 0;
1368 }
1369 return 1;
andre61e67252000-06-04 17:07:49 +00001370}
andre2ff7b5d2000-06-03 14:57:40 +00001371
1372static int
andre61e67252000-06-04 17:07:49 +00001373lastlog_perform_login(struct logininfo *li)
1374{
andre2ff7b5d2000-06-03 14:57:40 +00001375 struct lastlog last;
1376 int fd;
1377
1378 /* create our struct lastlog */
1379 lastlog_construct(li, &last);
1380
1381 /* write the entry */
Damien Miller53c5d462000-06-28 00:50:50 +10001382 if (lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) {
1383 if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
andre2ff7b5d2000-06-03 14:57:40 +00001384 log("lastlog_write_filemode: Error writing to %s: %s",
1385 LASTLOG_FILE, strerror(errno));
1386 return 0;
1387 }
1388 return 1;
Damien Millerdd47aa22000-06-27 11:18:27 +10001389 } else {
andre2ff7b5d2000-06-03 14:57:40 +00001390 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001391 }
andre61e67252000-06-04 17:07:49 +00001392}
andre2ff7b5d2000-06-03 14:57:40 +00001393
andre2ff7b5d2000-06-03 14:57:40 +00001394int
andre61e67252000-06-04 17:07:49 +00001395lastlog_write_entry(struct logininfo *li)
1396{
andre2ff7b5d2000-06-03 14:57:40 +00001397 switch(li->type) {
1398 case LTYPE_LOGIN:
1399 return lastlog_perform_login(li);
1400 default:
1401 log("lastlog_write_entry: Invalid type field");
1402 return 0;
1403 }
andre61e67252000-06-04 17:07:49 +00001404}
andre2ff7b5d2000-06-03 14:57:40 +00001405
andre2ff7b5d2000-06-03 14:57:40 +00001406static void
andre61e67252000-06-04 17:07:49 +00001407lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1408{
andre2ff7b5d2000-06-03 14:57:40 +00001409 line_fullname(li->line, last->ll_line, sizeof(li->line));
Damien Millerdd47aa22000-06-27 11:18:27 +10001410 strlcpy(li->hostname, last->ll_host,
andre6bb92372000-06-19 08:20:03 +00001411 MIN_SIZEOF(li->hostname, last->ll_host));
andre2ff7b5d2000-06-03 14:57:40 +00001412 li->tv_sec = last->ll_time;
andre61e67252000-06-04 17:07:49 +00001413}
andre2ff7b5d2000-06-03 14:57:40 +00001414
andre2ff7b5d2000-06-03 14:57:40 +00001415int
andre61e67252000-06-04 17:07:49 +00001416lastlog_get_entry(struct logininfo *li)
1417{
andre2ff7b5d2000-06-03 14:57:40 +00001418 struct lastlog last;
1419 int fd;
1420
1421 if (lastlog_openseek(li, &fd, O_RDONLY)) {
Damien Miller53c5d462000-06-28 00:50:50 +10001422 if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
1423 log("lastlog_get_entry: Error reading from %s: %s",
andre2ff7b5d2000-06-03 14:57:40 +00001424 LASTLOG_FILE, strerror(errno));
1425 return 0;
1426 } else {
1427 lastlog_populate_entry(li, &last);
1428 return 1;
1429 }
Damien Millerdd47aa22000-06-27 11:18:27 +10001430 } else {
andre2ff7b5d2000-06-03 14:57:40 +00001431 return 0;
Damien Millerdd47aa22000-06-27 11:18:27 +10001432 }
andre61e67252000-06-04 17:07:49 +00001433}
Damien Millerd5bf3072000-06-07 21:32:13 +10001434#endif /* USE_LASTLOG */