blob: 5951e02711486f9e68e7165f776eab89fe4a265c [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)
144 **
145 ** Testing required: Please send reports!
146 ** Solaris
147 ** IRIX
148 ** 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 Millerd5bf3072000-06-07 21:32:13 +1000173RCSID("$Id: loginrec.c,v 1.4 2000/06/07 11:32:13 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
201
202/**
203 ** platform-independent login functions
204 **/
205
andre61e67252000-06-04 17:07:49 +0000206/* Record a login */
207int
208login_login (struct logininfo *li)
209{
210 li->type = LTYPE_LOGIN;
211 return login_write(li);
212}
213
214
215/* Record a logout */
216int
217login_logout(struct logininfo *li)
218{
219 li->type = LTYPE_LOGOUT;
220 return login_write(li);
221}
222
223
224/* Retrieve the last login time for a user (or fake on from wtmp/wtmpx) */
225unsigned int
226login_get_lastlog_time(const int uid)
227{
228 struct logininfo li;
229
230 login_get_lastlog(&li, uid);
231 return li.tv_sec;
232}
233
234/* Retrieve a lastlog entry (or fake one from wtmp/wtmpx) */
235struct logininfo *
236login_get_lastlog(struct logininfo *li, const int uid)
237{
238 memset(li, '\0', sizeof(struct logininfo));
239 li->uid = uid;
240 if (getlast_entry(li))
241 return li;
242 else
243 return 0;
244}
245
246
andre2ff7b5d2000-06-03 14:57:40 +0000247/* login_alloc_entry() - allocate and initialise a logininfo */
andre61e67252000-06-04 17:07:49 +0000248struct
249logininfo *login_alloc_entry(int pid, const char *username,
250 const char *hostname, const char *line)
251{
andre2ff7b5d2000-06-03 14:57:40 +0000252 struct logininfo *newli;
253
254 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo));
andre61e67252000-06-04 17:07:49 +0000255 (void)login_init_entry(newli, pid, username, hostname, line);
256 return newli;
257}
andre2ff7b5d2000-06-03 14:57:40 +0000258
259
andre61e67252000-06-04 17:07:49 +0000260/* login_free_entry() - free struct memory (trivial) */
261void
262login_free_entry(struct logininfo *li)
263{
264 xfree(li);
265}
266
andre2ff7b5d2000-06-03 14:57:40 +0000267
268/* login_init_entry() - initialise a struct logininfo */
andre61e67252000-06-04 17:07:49 +0000269int
270login_init_entry(struct logininfo *li, int pid, const char *username,
271 const char *hostname, const char *line)
272{
andre2ff7b5d2000-06-03 14:57:40 +0000273 /* zero the structure */
274 memset(li, 0, sizeof(struct logininfo));
275
andre61e67252000-06-04 17:07:49 +0000276 li->pid = pid;
andre2ff7b5d2000-06-03 14:57:40 +0000277 /* set the line information */
andre61e67252000-06-04 17:07:49 +0000278 if (line)
andre2ff7b5d2000-06-03 14:57:40 +0000279 line_fullname(li->line, line, sizeof(li->line));
andre2ff7b5d2000-06-03 14:57:40 +0000280
andre61e67252000-06-04 17:07:49 +0000281 if (username)
andre2ff7b5d2000-06-03 14:57:40 +0000282 strlcpy(li->username, username, sizeof(li->username));
andre61e67252000-06-04 17:07:49 +0000283 if (hostname)
andre2ff7b5d2000-06-03 14:57:40 +0000284 strlcpy(li->hostname, hostname, sizeof(li->hostname));
andre61e67252000-06-04 17:07:49 +0000285 return 1;
andre2ff7b5d2000-06-03 14:57:40 +0000286}
287
288
289void
andre61e67252000-06-04 17:07:49 +0000290login_set_current_time(struct logininfo *li)
291{
andre2ff7b5d2000-06-03 14:57:40 +0000292#ifdef HAVE_SYS_TIME_H
293 struct timeval tv;
294
295 gettimeofday(&tv, NULL);
296 li->tv_sec = tv.tv_sec ; li->tv_usec = tv.tv_usec;
297#else
andre61e67252000-06-04 17:07:49 +0000298 time_t tm = time(0);
299
300 li->tv_sec = tm; li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +0000301#endif
302}
303
andre61e67252000-06-04 17:07:49 +0000304
305/* copy a sockaddr_* into our logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000306void
andre61e67252000-06-04 17:07:49 +0000307login_set_addr(struct logininfo *li, const struct sockaddr *sa,
308 const unsigned int sa_size)
309{
310 unsigned int bufsize = sa_size;
311
312 /* make sure we don't overrun our union */
313 if (sizeof(li->hostaddr) < sa_size)
314 bufsize = sizeof(li->hostaddr);
315
316 memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
andre2ff7b5d2000-06-03 14:57:40 +0000317}
318
andre2ff7b5d2000-06-03 14:57:40 +0000319
andre61e67252000-06-04 17:07:49 +0000320/**
321 ** login_write: Call low-level recording functions based on autoconf
322 ** results
323 **/
andre2ff7b5d2000-06-03 14:57:40 +0000324
325int
andre61e67252000-06-04 17:07:49 +0000326login_write (struct logininfo *li)
327{
andre2ff7b5d2000-06-03 14:57:40 +0000328 if ((int)geteuid() != 0) {
329 log("Attempt to write login records by non-root user (aborting)");
330 return 1;
331 }
332 /* set the timestamp */
333 login_set_current_time(li);
334#ifdef USE_LOGIN
335 syslogin_write_entry(li);
336#endif
337#ifdef USE_LASTLOG
338 if (li->type == LTYPE_LOGIN) {
339 lastlog_write_entry(li);
340 }
341#endif
342#ifdef USE_UTMP
343 utmp_write_entry(li);
344#endif
345#ifdef USE_WTMP
346 wtmp_write_entry(li);
347#endif
348#ifdef USE_UTMPX
349 utmpx_write_entry(li);
350#endif
351#ifdef USE_WTMPX
352 wtmpx_write_entry(li);
353#endif
354 return 0;
355}
356
andre2ff7b5d2000-06-03 14:57:40 +0000357
358/**
andre61e67252000-06-04 17:07:49 +0000359 ** getlast_entry: Call low-level functions to retrieve the last login
360 ** time.
andre2ff7b5d2000-06-03 14:57:40 +0000361 **/
362
andre61e67252000-06-04 17:07:49 +0000363/* take the uid in li and return the last login time */
364int
365getlast_entry(struct logininfo *li)
366{
367#ifdef USE_LASTLOG
368 if (lastlog_get_entry(li))
369 return 1;
370 else
371 return 0;
372#else
373 /* !USE_LASTLOG */
374
375 /* Try to retrieve the last login time from wtmp */
376# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
377 /* retrieve last login time from utmp */
378 if (wtmp_get_entry(li))
379 return 1;
380 else
381 return 0;
382# else
383
384 /* If wtmp isn't available, try wtmpx */
385
386# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
387 /* retrieve last login time from utmpx */
388 if (wtmpx_get_entry(li))
389 return 1;
390 else
391 return 0;
392# else
393
394 /* Give up: No means of retrieving last login time */
395 return 0;
396# endif
397# endif
398#endif
399/* USE_LASTLOG */
400}
401
402
403
andre2ff7b5d2000-06-03 14:57:40 +0000404/*
andre61e67252000-06-04 17:07:49 +0000405 * 'line' string utility functions
406 *
407 * These functions process the 'line' string into one of three forms:
408 *
andre2ff7b5d2000-06-03 14:57:40 +0000409 * 1. The full filename (including '/dev')
410 * 2. The stripped name (excluding '/dev')
andre61e67252000-06-04 17:07:49 +0000411 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
412 * /dev/pts/1 -> ts/1 )
andre2ff7b5d2000-06-03 14:57:40 +0000413 *
414 * Form 3 is used on some systems to identify a .tmp.? entry when
415 * attempting to remove it. Typically both addition and removal is
andre61e67252000-06-04 17:07:49 +0000416 * performed by one application - say, sshd - so as long as the choice
417 * uniquely identifies a terminal it's ok.
andre2ff7b5d2000-06-03 14:57:40 +0000418 */
419
420
andre61e67252000-06-04 17:07:49 +0000421/* line_fullname(): add the leading '/dev/' if it doesn't exist make
422 * sure dst has enough space, if not just copy src (ugh) */
andre2ff7b5d2000-06-03 14:57:40 +0000423char *
andre61e67252000-06-04 17:07:49 +0000424line_fullname(char *dst, const char *src, int dstsize)
425{
andre2ff7b5d2000-06-03 14:57:40 +0000426 memset(dst, '\0', dstsize);
427 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
428 strlcpy(dst, src, dstsize);
429 else {
430 strlcpy(dst, "/dev/", 5);
431 strlcat(dst, src, dstsize);
432 }
433 return dst;
434}
435
andre61e67252000-06-04 17:07:49 +0000436
437/* line_stripname(): strip the leading '/dev' if it exists, return dst */
andre2ff7b5d2000-06-03 14:57:40 +0000438char *
andre61e67252000-06-04 17:07:49 +0000439line_stripname(char *dst, const char *src, int dstsize)
440{
andre2ff7b5d2000-06-03 14:57:40 +0000441 memset(dst, '\0', dstsize);
442 if (strncmp(src, "/dev/", 5) == 0)
443 strlcpy(dst, &src[5], dstsize);
444 else
445 strlcpy(dst, src, dstsize);
446 return dst;
andre61e67252000-06-04 17:07:49 +0000447}
448
andre2ff7b5d2000-06-03 14:57:40 +0000449
andre61e67252000-06-04 17:07:49 +0000450/* line_abbrevname(): Return the abbreviated (usually four-character)
451 * form of the line (Just use the last <dstsize> characters of the
452 * full name.)
453 *
454 * NOTE: use strncpy because we do NOT necessarily want zero
455 * termination */
andre2ff7b5d2000-06-03 14:57:40 +0000456char *
457line_abbrevname(char *dst, const char *src, int dstsize) {
458 memset(dst, '\0', dstsize);
andre61e67252000-06-04 17:07:49 +0000459 src += (strlen(src) - dstsize);
460 strncpy(dst, src, dstsize); /* note: _don't_ change this to strlcpy */
andre2ff7b5d2000-06-03 14:57:40 +0000461 return dst;
462}
463
464
465/**
466 ** utmp utility functions
andre61e67252000-06-04 17:07:49 +0000467 **
468 ** These functions manipulate struct utmp, taking system differences
469 ** into account.
andre2ff7b5d2000-06-03 14:57:40 +0000470 **/
471
472#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
473
andre2ff7b5d2000-06-03 14:57:40 +0000474/* build the utmp structure */
475void
andre61e67252000-06-04 17:07:49 +0000476set_utmp_time(struct logininfo *li, struct utmp *ut)
477{
andre2ff7b5d2000-06-03 14:57:40 +0000478#ifdef HAVE_TV_IN_UTMP
479 ut->ut_tv.tv_sec = li->tv_sec;
480 ut->ut_tv.tv_usec = li->tv_usec;
481#else
482# ifdef HAVE_TIME_IN_UTMP
483 ut->ut_time = li->tv_sec;
484# endif
485#endif
486}
487
andre61e67252000-06-04 17:07:49 +0000488
andre2ff7b5d2000-06-03 14:57:40 +0000489void
490construct_utmp(struct logininfo *li,
andre61e67252000-06-04 17:07:49 +0000491 struct utmp *ut)
492{
andre2ff7b5d2000-06-03 14:57:40 +0000493 memset(ut, '\0', sizeof(struct utmp));
andre2ff7b5d2000-06-03 14:57:40 +0000494#ifdef HAVE_ID_IN_UTMP
495 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
496#endif
497
498#ifdef HAVE_TYPE_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000499 /* This is done here to keep utmp constants out of login.h */
andre2ff7b5d2000-06-03 14:57:40 +0000500 switch (li->type) {
501 case LTYPE_LOGIN:
502 ut->ut_type = USER_PROCESS;
503 break;
504 case LTYPE_LOGOUT:
505 ut->ut_type = DEAD_PROCESS;
506 break;
507 }
508#endif
509
510#ifdef HAVE_PID_IN_UTMP
511 ut->ut_pid = li->pid;
512#endif
513 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
514 strlcpy(ut->ut_name, li->username, sizeof(ut->ut_name));
515 set_utmp_time(li, ut);
516#ifdef HAVE_HOST_IN_UTMP
517 strlcpy(ut->ut_host, li->hostname, sizeof(ut->ut_host));
518#endif
519#ifdef HAVE_ADDR_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000520 /* this is just a 32-bit IP address */
521 if (li->hostaddr.sa.sa_family == AF_INET)
522 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
523#endif
524}
andre2ff7b5d2000-06-03 14:57:40 +0000525
526#endif
527/* USE_UTMP || USE_WTMP || USE_LOGIN */
528
andre61e67252000-06-04 17:07:49 +0000529
530
andre2ff7b5d2000-06-03 14:57:40 +0000531/**
532 ** utmpx utility functions
andre61e67252000-06-04 17:07:49 +0000533 **
534 ** These functions manipulate struct utmpx, accounting for system
535 ** variations.
andre2ff7b5d2000-06-03 14:57:40 +0000536 **/
537
538#if defined(USE_UTMPX) || defined (USE_WTMPX)
539
andre2ff7b5d2000-06-03 14:57:40 +0000540/* build the utmpx structure */
541void
andre61e67252000-06-04 17:07:49 +0000542set_utmpx_time(struct logininfo *li, struct utmpx *utx)
543{
andre2ff7b5d2000-06-03 14:57:40 +0000544#ifdef HAVE_TV_IN_UTMPX
545 utx->ut_tv.tv_sec = li->tv_sec;
546 utx->ut_tv.tv_usec = li->tv_usec;
547#else
548# ifdef HAVE_TIME_IN_UTMPX
549 utx->ut_time = li->tv_sec;
550# endif
551#endif
552}
553
andre2ff7b5d2000-06-03 14:57:40 +0000554
andre61e67252000-06-04 17:07:49 +0000555void
556construct_utmpx(struct logininfo *li, struct utmpx *utx)
557{
558 memset(utx, '\0', sizeof(struct utmpx));
andre2ff7b5d2000-06-03 14:57:40 +0000559 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
560
561 /* this is done here to keep utmp constants out of loginrec.h */
562 switch (li->type) {
563 case LTYPE_LOGIN:
564 utx->ut_type = USER_PROCESS;
565 break;
566 case LTYPE_LOGOUT:
567 utx->ut_type = DEAD_PROCESS;
568 break;
569 }
andre2ff7b5d2000-06-03 14:57:40 +0000570 utx->ut_pid = li->pid;
571 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
572 strlcpy(utx->ut_name, li->username, sizeof(utx->ut_name));
573 set_utmpx_time(li, utx);
574#ifdef HAVE_HOST_IN_UTMPX
575 strlcpy(utx->ut_host, li->hostname, sizeof(utx->ut_host));
576#endif
577#ifdef HAVE_ADDR_IN_UTMPX
andre61e67252000-06-04 17:07:49 +0000578 /* FIXME: (ATL) not supported yet */
andre2ff7b5d2000-06-03 14:57:40 +0000579#endif
580#ifdef HAVE_SYSLEN_IN_UTMPX
581 /* this is safe because of the extra nulls in logininfo */
582 utx->ut_syslen = strlen(li->hostname);
583#endif
andre61e67252000-06-04 17:07:49 +0000584}
andre2ff7b5d2000-06-03 14:57:40 +0000585
586#endif
587/* USE_UTMPX || USE_WTMPX */
588
589
590
591/**
andre61e67252000-06-04 17:07:49 +0000592 ** Low-level utmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000593 **/
594
595/* FIXME: (ATL) utmp_write_direct needs testing */
596
597#ifdef USE_UTMP
598
andre2ff7b5d2000-06-03 14:57:40 +0000599/* if we can, use pututline() etc. */
600#if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
601 defined(HAVE_PUTUTLINE)
602# define UTMP_USE_LIBRARY
603#endif
604
605
606/* write a utmp entry with the system's help (pututline() and pals) */
607#ifdef UTMP_USE_LIBRARY
608static int
andre61e67252000-06-04 17:07:49 +0000609utmp_write_library(struct logininfo *li, struct utmp *ut)
610{
andre2ff7b5d2000-06-03 14:57:40 +0000611 setutent();
612 pututline(ut);
613
614#ifdef HAVE_ENDUTENT
615 endutent();
616#endif
617 return 1;
andre61e67252000-06-04 17:07:49 +0000618}
andre2ff7b5d2000-06-03 14:57:40 +0000619
620#else
621
622/* write a utmp entry direct to the file */
andre61e67252000-06-04 17:07:49 +0000623/* This is a slightly modification of code in OpenBSD's login.c */
andre2ff7b5d2000-06-03 14:57:40 +0000624static int
andre61e67252000-06-04 17:07:49 +0000625utmp_write_direct(struct logininfo *li, struct utmp *ut)
626{
andre2ff7b5d2000-06-03 14:57:40 +0000627 struct utmp old_ut;
628 register int fd;
629 int tty;
630
631 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
632
633 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
634 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
635 /*
636 * Prevent luser from zero'ing out ut_host.
637 * If the new ut_line is empty but the old one is not
638 * and ut_line and ut_name match, preserve the old ut_line.
639 */
640 if ( read(fd, &old_ut, sizeof(struct utmp)) == sizeof(struct utmp)
641 && ut->ut_host[0] == '\0'
642 && old_ut.ut_host[0] != '\0'
643 && strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0
644 && strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0 )
645 (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
646
647 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
648 if (write(fd, ut, sizeof(struct utmp))==-1)
649 log("utmp_write_direct: error writing %s: %s",
650 UTMP_FILE, strerror(errno));
651
652 (void)close(fd);
653 return 1;
654 } else
655 return 0;
andre61e67252000-06-04 17:07:49 +0000656}
andre2ff7b5d2000-06-03 14:57:40 +0000657#endif /* UTMP_USE_LIBRARY */
658
659
660static int
andre61e67252000-06-04 17:07:49 +0000661utmp_perform_login(struct logininfo *li)
662{
andre2ff7b5d2000-06-03 14:57:40 +0000663 struct utmp ut;
664
665 construct_utmp(li, &ut);
andre2ff7b5d2000-06-03 14:57:40 +0000666#ifdef UTMP_USE_LIBRARY
667 if (!utmp_write_library(li, &ut)) {
668 log("utmp_perform_login: utmp_write_library() failed");
669 return 0;
670 }
671#else
672 if (!utmp_write_direct(li, &ut)) {
673 log("utmp_perform_login: utmp_write_direct() failed");
674 return 0;
675 }
676#endif
677 return 1;
andre61e67252000-06-04 17:07:49 +0000678}
andre2ff7b5d2000-06-03 14:57:40 +0000679
680
681static int
andre61e67252000-06-04 17:07:49 +0000682utmp_perform_logout(struct logininfo *li)
683{
andre2ff7b5d2000-06-03 14:57:40 +0000684 struct utmp ut;
685
686 memset(&ut, '\0', sizeof(ut));
687 set_utmp_time(li, &ut);
688 line_stripname(ut.ut_line, li->line, sizeof(ut.ut_line));
689#ifdef HAVE_ID_IN_UTMP
690 line_abbrevname(ut.ut_id, li->line, sizeof(ut.ut_id));
691#endif
692#ifdef HAVE_TYPE_IN_UTMP
693 ut.ut_type = DEAD_PROCESS;
694#endif
695
696#if !defined(DISABLE_PUTUTLINE) \
697 && defined(HAVE_SETUTENT) && defined(HAVE_PUTUTLINE)
698 utmp_write_library(li, &ut);
699#else
700 utmp_write_direct(li, &ut);
701#endif
702
703 return 1;
andre61e67252000-06-04 17:07:49 +0000704}
andre2ff7b5d2000-06-03 14:57:40 +0000705
706
707int
andre61e67252000-06-04 17:07:49 +0000708utmp_write_entry(struct logininfo *li)
709{
andre2ff7b5d2000-06-03 14:57:40 +0000710 switch(li->type) {
711 case LTYPE_LOGIN:
712 return utmp_perform_login(li);
713
714 case LTYPE_LOGOUT:
715 return utmp_perform_logout(li);
716
717 default:
718 log("utmp_write_entry: invalid type field");
719 return 0;
720 }
andre61e67252000-06-04 17:07:49 +0000721}
andre2ff7b5d2000-06-03 14:57:40 +0000722
723
724#endif
725/* USE_UTMP */
726
727
728/**
andre61e67252000-06-04 17:07:49 +0000729 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000730 **/
731
732/* not much point if we don't want utmpx entries */
733#ifdef USE_UTMPX
734
andre2ff7b5d2000-06-03 14:57:40 +0000735/* if we have the wherewithall, use pututxline etc. */
736#if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) \
737 && defined(HAVE_PUTUTXLINE)
738# define UTMPX_USE_LIBRARY
739#endif
740
741
742/* write a utmpx entry with the system's help (pututxline() and pals) */
743#ifdef UTMPX_USE_LIBRARY
744static int
andre61e67252000-06-04 17:07:49 +0000745utmpx_write_library(struct logininfo *li, struct utmpx *utx)
746{
andre2ff7b5d2000-06-03 14:57:40 +0000747 setutxent();
748 pututxline(utx);
749
750#ifdef HAVE_ENDUTXENT
751 endutxent();
752#endif
753 return 1;
andre61e67252000-06-04 17:07:49 +0000754}
andre2ff7b5d2000-06-03 14:57:40 +0000755
756#else
757/* UTMPX_USE_LIBRARY */
758
759
760/* write a utmp entry direct to the file */
761static int
andre61e67252000-06-04 17:07:49 +0000762utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
763{
andre2ff7b5d2000-06-03 14:57:40 +0000764 log("utmpx_write_direct: not implemented!");
765 return 0;
andre61e67252000-06-04 17:07:49 +0000766}
andre2ff7b5d2000-06-03 14:57:40 +0000767
768#endif
769/* UTMPX_USE_LIBRARY */
770
771static int
andre61e67252000-06-04 17:07:49 +0000772utmpx_perform_login(struct logininfo *li)
773{
andre2ff7b5d2000-06-03 14:57:40 +0000774 struct utmpx utx;
775
776 construct_utmpx(li, &utx);
andre2ff7b5d2000-06-03 14:57:40 +0000777#ifdef UTMPX_USE_LIBRARY
778 if (!utmpx_write_library(li, &utx)) {
779 log("utmpx_perform_login: utmp_write_library() failed");
780 return 0;
781 }
782#else
783 if (!utmpx_write_direct(li, &ut)) {
784 log("utmpx_perform_login: utmp_write_direct() failed");
785 return 0;
786 }
787#endif
788 return 1;
andre61e67252000-06-04 17:07:49 +0000789}
andre2ff7b5d2000-06-03 14:57:40 +0000790
791
792static int
andre61e67252000-06-04 17:07:49 +0000793utmpx_perform_logout(struct logininfo *li)
794{
andre2ff7b5d2000-06-03 14:57:40 +0000795 struct utmpx utx;
796
797 memset(&utx, '\0', sizeof(utx));
798 set_utmpx_time(li, &utx);
799 line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
800#ifdef HAVE_ID_IN_UTMPX
801 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
802#endif
803#ifdef HAVE_TYPE_IN_UTMPX
804 utx.ut_type = DEAD_PROCESS;
805#endif
806
807#ifdef UTMPX_USE_LIBRARY
808 utmpx_write_library(li, &utx);
809#else
810 utmpx_write_direct(li, &utx);
811#endif
andre2ff7b5d2000-06-03 14:57:40 +0000812 return 1;
andre61e67252000-06-04 17:07:49 +0000813}
andre2ff7b5d2000-06-03 14:57:40 +0000814
815
816int
andre61e67252000-06-04 17:07:49 +0000817utmpx_write_entry(struct logininfo *li)
818{
andre2ff7b5d2000-06-03 14:57:40 +0000819 switch(li->type) {
820 case LTYPE_LOGIN:
821 return utmpx_perform_login(li);
822 case LTYPE_LOGOUT:
823 return utmpx_perform_logout(li);
824 default:
825 log("utmpx_write_entry: invalid type field");
826 return 0;
827 }
andre61e67252000-06-04 17:07:49 +0000828}
andre2ff7b5d2000-06-03 14:57:40 +0000829
830
831#endif
832/* USE_UTMPX */
833
834
835/**
andre61e67252000-06-04 17:07:49 +0000836 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000837 **/
838
839#ifdef USE_WTMP
840
andre2ff7b5d2000-06-03 14:57:40 +0000841/* write a wtmp entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000842/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000843static int
andre61e67252000-06-04 17:07:49 +0000844wtmp_write(struct logininfo *li, struct utmp *ut)
845{
andre2ff7b5d2000-06-03 14:57:40 +0000846 struct stat buf;
847 int fd, ret = 1;
848
849 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
850 log("wtmp_write: problem writing %s: %s",
851 WTMP_FILE, strerror(errno));
852 return 0;
853 }
andre61e67252000-06-04 17:07:49 +0000854 if (fstat(fd, &buf) == 0)
andre2ff7b5d2000-06-03 14:57:40 +0000855 if (write(fd, (char *)ut, sizeof(struct utmp)) !=
856 sizeof(struct utmp)) {
857 ftruncate(fd, buf.st_size);
858 log("wtmp_write: problem writing %s: %s",
859 WTMP_FILE, strerror(errno));
860 ret = 0;
861 }
862 (void)close(fd);
andre2ff7b5d2000-06-03 14:57:40 +0000863 return ret;
andre61e67252000-06-04 17:07:49 +0000864}
andre2ff7b5d2000-06-03 14:57:40 +0000865
866
867static int
andre61e67252000-06-04 17:07:49 +0000868wtmp_perform_login(struct logininfo *li){
andre2ff7b5d2000-06-03 14:57:40 +0000869 struct utmp ut;
870
871 construct_utmp(li, &ut);
872 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000873}
andre2ff7b5d2000-06-03 14:57:40 +0000874
875
876static int
andre61e67252000-06-04 17:07:49 +0000877wtmp_perform_logout(struct logininfo *li)
878{
andre2ff7b5d2000-06-03 14:57:40 +0000879 struct utmp ut;
880
881 construct_utmp(li, &ut);
882 /* blank out unnecessary fields */
883 memset(&(ut.ut_name), '\0', sizeof(ut.ut_name));
884#ifdef HAVE_ID_IN_UTMP
885 memset(&(ut.ut_id), '\0', sizeof(ut.ut_id));
886#endif
887#ifdef HAVE_HOST_IN_UTMP
888 memset(&(ut.ut_host), '\0', sizeof(ut.ut_host));
889#endif
890#ifdef HAVE_ADDR_IN_UTMP
891 memset(&(ut.ut_addr), '\0', sizeof(ut.ut_addr));
892#endif
893 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000894}
andre2ff7b5d2000-06-03 14:57:40 +0000895
896
897int
andre61e67252000-06-04 17:07:49 +0000898wtmp_write_entry(struct logininfo *li)
899{
andre2ff7b5d2000-06-03 14:57:40 +0000900 switch(li->type) {
901 case LTYPE_LOGIN:
902 return wtmp_perform_login(li);
903 case LTYPE_LOGOUT:
904 return wtmp_perform_logout(li);
905 default:
906 log("wtmp_write_entry: invalid type field");
907 return 0;
908 }
andre61e67252000-06-04 17:07:49 +0000909}
andre2ff7b5d2000-06-03 14:57:40 +0000910
911
912int
andre61e67252000-06-04 17:07:49 +0000913wtmp_get_entry(struct logininfo *li)
914{
andre2ff7b5d2000-06-03 14:57:40 +0000915 struct stat st;
916 struct utmp ut;
917 int fd;
918
919 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
920 log("wtmp_get_entry: problem opening %s: %s",
921 WTMP_FILE, strerror(errno));
922 return 0;
923 }
andre61e67252000-06-04 17:07:49 +0000924 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +0000925 log("wtmp_get_entry: couldn't stat %s: %s",
926 WTMP_FILE, strerror(errno));
927 close(fd);
928 return 0;
929 }
andre2ff7b5d2000-06-03 14:57:40 +0000930 (void)lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END);
931
932 do {
933 if (read(fd, &ut, sizeof(ut)) != sizeof(ut)) {
934 log("wtmp_get_entry: read of %s failed: %s",
935 WTMP_FILE, strerror(errno));
936 close (fd);
937 return 0;
938 }
andre2ff7b5d2000-06-03 14:57:40 +0000939 /* Logouts are recorded as a blank username on a particular line.
940 * So, we just need to find the username in struct utmp */
941 if ( strncmp(li->username, ut.ut_user, 8) == 0 ) {
942 /* note we've already made sure there's a time in struct utmp */
943#ifdef HAVE_TIME_IN_UTMP
944 li->tv_sec = ut.ut_time;
945#else
946# if HAVE_TV_IN_UTMP
947 li->tv_sec = ut.ut_tv.tv_sec;
948# endif
949#endif
950 line_fullname(li->line, ut.ut_line, sizeof(ut.ut_line));
951#ifdef HAVE_HOST_IN_UTMP
952 strlcpy(li->hostname, ut.ut_host, sizeof(ut.ut_host));
953#endif
954 }
955 if (lseek(fd, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1) {
956 close (fd);
957 return 0;
958 }
959 } while (li->tv_sec == 0);
960
961 return 1;
andre61e67252000-06-04 17:07:49 +0000962}
andre2ff7b5d2000-06-03 14:57:40 +0000963
964
965#endif
966/* USE_WTMP */
967
968
969/**
andre61e67252000-06-04 17:07:49 +0000970 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000971 **/
972
973#ifdef USE_WTMPX
974
andre2ff7b5d2000-06-03 14:57:40 +0000975/* write a wtmpx entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000976/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000977static int
andre61e67252000-06-04 17:07:49 +0000978wtmpx_write(struct logininfo *li, struct utmpx *utx)
979{
andre2ff7b5d2000-06-03 14:57:40 +0000980 struct stat buf;
981 int fd, ret = 1;
982
983 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
984 log("wtmpx_write: problem opening %s: %s",
985 WTMPX_FILE, strerror(errno));
986 return 0;
987 }
988
989 if (fstat(fd, &buf) == 0)
990 if (write(fd, (char *)utx, sizeof(struct utmpx)) !=
991 sizeof(struct utmpx)) {
992 ftruncate(fd, buf.st_size);
993 log("wtmpx_write: problem writing %s: %s",
994 WTMPX_FILE, strerror(errno));
995 ret = 0;
996 }
997 (void)close(fd);
998
999 return ret;
andre61e67252000-06-04 17:07:49 +00001000}
andre2ff7b5d2000-06-03 14:57:40 +00001001
1002
1003static int
andre61e67252000-06-04 17:07:49 +00001004wtmpx_perform_login(struct logininfo *li)
1005{
andre2ff7b5d2000-06-03 14:57:40 +00001006 struct utmpx utx;
1007
1008 construct_utmpx(li, &utx);
1009 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001010}
andre2ff7b5d2000-06-03 14:57:40 +00001011
1012
1013static int
andre61e67252000-06-04 17:07:49 +00001014wtmpx_perform_logout(struct logininfo *li)
1015{
andre2ff7b5d2000-06-03 14:57:40 +00001016 struct utmpx utx;
1017
1018 construct_utmpx(li, &utx);
1019 /* blank out unnecessary fields */
1020 memset(&(utx.ut_name), '\0', sizeof(utx.ut_name));
1021#ifdef HAVE_ID_IN_UTMPX
1022 memset(&(utx.ut_id), '\0', sizeof(utx.ut_id));
1023#endif
1024#ifdef HAVE_HOST_IN_UTMPX
1025 memset(&(utx.ut_host), '\0', sizeof(utx.ut_host));
1026#endif
1027#ifdef HAVE_ADDR_IN_UTMPX
1028 memset(&(utx.ut_addr), '\0', sizeof(utx.ut_addr));
1029#endif
1030 return wtmpx_write(li, &utx);
1031
andre61e67252000-06-04 17:07:49 +00001032}
andre2ff7b5d2000-06-03 14:57:40 +00001033
1034
1035int
andre61e67252000-06-04 17:07:49 +00001036wtmpx_write_entry(struct logininfo *li)
1037{
andre2ff7b5d2000-06-03 14:57:40 +00001038 switch(li->type) {
1039 case LTYPE_LOGIN:
1040 return wtmpx_perform_login(li);
1041 case LTYPE_LOGOUT:
1042 return wtmpx_perform_logout(li);
1043 default:
1044 log("wtmpx_write_entry: invalid type field");
1045 return 0;
1046 }
andre61e67252000-06-04 17:07:49 +00001047}
andre2ff7b5d2000-06-03 14:57:40 +00001048
1049
1050int
andre61e67252000-06-04 17:07:49 +00001051wtmpx_get_entry(struct logininfo *li)
1052{
andre2ff7b5d2000-06-03 14:57:40 +00001053 struct stat st;
1054 struct utmpx utx;
1055 int fd;
1056
1057 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1058 log("wtmpx_get_entry: problem opening %s: %s",
1059 WTMPX_FILE, strerror(errno));
1060 return 0;
1061 }
andre61e67252000-06-04 17:07:49 +00001062 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001063 log("wtmpx_get_entry: couldn't stat %s: %s",
1064 WTMP_FILE, strerror(errno));
1065 close(fd);
1066 return 0;
1067 }
andre2ff7b5d2000-06-03 14:57:40 +00001068 (void)lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END);
1069
1070 do {
1071 if (read(fd, &utx, sizeof(utx)) != sizeof(utx)) {
1072 log("wtmpx_get_entry: read of %s failed: %s",
1073 WTMPX_FILE, strerror(errno));
1074 close (fd);
1075 return 0;
1076 }
andre2ff7b5d2000-06-03 14:57:40 +00001077 /* Logouts are recorded as a blank username on a particular line.
1078 * So, we just need to find the username in struct utmpx */
1079 if ( strncmp(li->username, utx.ut_user, 8) == 0 ) {
1080 /* note we've already made sure there's a time in struct utmp */
1081#ifdef HAVE_TV_IN_UTMPX
1082 li->tv_sec = utx.ut_tv.tv_sec;
1083#else
1084# ifdef HAVE_TIME_IN_UTMPX
1085 li->tv_sec = utx.ut_time;
1086# endif
1087#endif
1088 line_fullname(li->line, utx.ut_line, sizeof(utx.ut_line));
1089#ifdef HAVE_HOST_IN_UTMPX
1090 strlcpy(li->hostname, utx.ut_host, sizeof(utx.ut_line));
1091#endif
1092 }
1093 if (lseek(fd, (off_t)(0-2*sizeof(struct utmpx)), SEEK_CUR) == -1) {
1094 close (fd);
1095 return 0;
1096 }
1097 } while (li->tv_sec == 0);
1098 return 1;
andre61e67252000-06-04 17:07:49 +00001099}
andre2ff7b5d2000-06-03 14:57:40 +00001100
1101
Damien Millerd5bf3072000-06-07 21:32:13 +10001102#endif /* USE_WTMPX */
andre2ff7b5d2000-06-03 14:57:40 +00001103
1104
1105/**
andre61e67252000-06-04 17:07:49 +00001106 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001107 **/
1108
1109#ifdef USE_LOGIN
1110
andre2ff7b5d2000-06-03 14:57:40 +00001111static int
andre61e67252000-06-04 17:07:49 +00001112syslogin_perform_login(struct logininfo *li)
1113{
andre2ff7b5d2000-06-03 14:57:40 +00001114 struct utmp *ut;
1115
1116 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) {
1117 log("syslogin_perform_login: couldn't malloc()");
1118 return 0;
1119 }
1120 construct_utmp(li, ut);
1121 login(ut);
1122
1123 return 1;
andre61e67252000-06-04 17:07:49 +00001124}
1125
andre2ff7b5d2000-06-03 14:57:40 +00001126
1127static int
andre61e67252000-06-04 17:07:49 +00001128syslogin_perform_logout(struct logininfo *li)
1129{
andre2ff7b5d2000-06-03 14:57:40 +00001130#ifdef HAVE_LOGOUT
1131 char line[8];
1132
1133 (void)line_stripname(line, li->line, sizeof(line));
1134
1135 if (!logout(line)) {
1136 log("syslogin_perform_logout: logout() returned an error");
Damien Millerd5bf3072000-06-07 21:32:13 +10001137# ifdef HAVE_LOGWTMP
andre2ff7b5d2000-06-03 14:57:40 +00001138 } else {
1139 logwtmp(line, "", "");
1140 }
Damien Millerd5bf3072000-06-07 21:32:13 +10001141# endif
andre2ff7b5d2000-06-03 14:57:40 +00001142 /* TODO: what to do if we have login, but no logout?
1143 * what if logout but no logwtmp? All routines are in libutil
1144 * so they should all be there, but... */
1145#endif
1146 return 1;
andre61e67252000-06-04 17:07:49 +00001147}
andre2ff7b5d2000-06-03 14:57:40 +00001148
1149
1150int
andre61e67252000-06-04 17:07:49 +00001151syslogin_write_entry(struct logininfo *li)
1152{
andre2ff7b5d2000-06-03 14:57:40 +00001153 switch (li->type) {
1154 case LTYPE_LOGIN:
1155 return syslogin_perform_login(li);
1156 case LTYPE_LOGOUT:
1157 return syslogin_perform_logout(li);
1158 default:
1159 log("syslogin_write_entry: Invalid type field");
1160 return 0;
1161 }
andre61e67252000-06-04 17:07:49 +00001162}
andre2ff7b5d2000-06-03 14:57:40 +00001163
1164
Damien Millerd5bf3072000-06-07 21:32:13 +10001165#endif /* USE_LOGIN */
andre2ff7b5d2000-06-03 14:57:40 +00001166
1167/* end of file log-syslogin.c */
1168
1169
1170/**
andre61e67252000-06-04 17:07:49 +00001171 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001172 **/
1173
1174#ifdef USE_LASTLOG
1175
andre2ff7b5d2000-06-03 14:57:40 +00001176static void
andre61e67252000-06-04 17:07:49 +00001177lastlog_construct(struct logininfo *li, struct lastlog *last)
1178{
andre2ff7b5d2000-06-03 14:57:40 +00001179 /* clear the structure */
1180 memset(last, '\0', sizeof(struct lastlog));
1181
1182 (void)line_stripname(last->ll_line, li->line,
1183 sizeof(last->ll_line));
1184 strlcpy(last->ll_host, li->hostname, sizeof(last->ll_host));
1185 last->ll_time = li->tv_sec;
andre61e67252000-06-04 17:07:49 +00001186}
andre2ff7b5d2000-06-03 14:57:40 +00001187
1188
1189#define LL_FILE 1
1190#define LL_DIR 2
1191#define LL_OTHER 3
1192
1193static int
andre61e67252000-06-04 17:07:49 +00001194lastlog_filetype(char *filename)
1195{
andre2ff7b5d2000-06-03 14:57:40 +00001196 struct stat st;
1197
1198 if ( stat(LASTLOG_FILE, &st) != 0) {
1199 log("lastlog_perform_login: Couldn't stat %s: %s",
1200 LASTLOG_FILE, strerror(errno));
1201 return 0;
1202 }
andre2ff7b5d2000-06-03 14:57:40 +00001203 if (S_ISDIR(st.st_mode))
1204 return LL_DIR;
1205 else if (S_ISREG(st.st_mode))
1206 return LL_FILE;
1207 else
1208 return LL_OTHER;
andre61e67252000-06-04 17:07:49 +00001209}
andre2ff7b5d2000-06-03 14:57:40 +00001210
1211
1212/* open the file (using filemode) and seek to the login entry */
1213static int
andre61e67252000-06-04 17:07:49 +00001214lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1215{
andre2ff7b5d2000-06-03 14:57:40 +00001216 off_t offset;
1217 int type;
1218 char lastlog_file[1024];
1219
1220 type = lastlog_filetype(LASTLOG_FILE);
1221 switch (type) {
1222 case LL_FILE:
1223 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1224 break;
1225 case LL_DIR:
1226 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1227 LASTLOG_FILE, li->username);
1228 break;
1229 default:
1230 log("lastlog_openseek: %.100s is not a file or directory!",
1231 LASTLOG_FILE);
1232 return 0;
1233 } /* switch */
1234
1235 *fd = open(lastlog_file, filemode);
1236 if ( *fd < 0) {
1237 log("lastlog_openseek: Couldn't open %s: %s",
1238 lastlog_file, strerror(errno));
1239 return 0;
1240 }
andre2ff7b5d2000-06-03 14:57:40 +00001241 /* find this uid's offset in the lastlog file */
1242 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
1243
1244 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1245 log("lastlog_openseek: %s->lseek(): %s",
1246 lastlog_file, strerror(errno));
1247 return 0;
1248 }
1249 return 1;
andre61e67252000-06-04 17:07:49 +00001250}
andre2ff7b5d2000-06-03 14:57:40 +00001251
1252static int
andre61e67252000-06-04 17:07:49 +00001253lastlog_perform_login(struct logininfo *li)
1254{
andre2ff7b5d2000-06-03 14:57:40 +00001255 struct lastlog last;
1256 int fd;
1257
1258 /* create our struct lastlog */
1259 lastlog_construct(li, &last);
1260
1261 /* write the entry */
1262 if (lastlog_openseek(li, &fd, O_RDWR)) {
1263 if ( write(fd, &last, sizeof(struct lastlog))
1264 != sizeof(struct lastlog) ) {
1265 log("lastlog_write_filemode: Error writing to %s: %s",
1266 LASTLOG_FILE, strerror(errno));
1267 return 0;
1268 }
1269 return 1;
1270 } else
1271 return 0;
andre61e67252000-06-04 17:07:49 +00001272}
andre2ff7b5d2000-06-03 14:57:40 +00001273
1274
1275int
andre61e67252000-06-04 17:07:49 +00001276lastlog_write_entry(struct logininfo *li)
1277{
andre2ff7b5d2000-06-03 14:57:40 +00001278 switch(li->type) {
1279 case LTYPE_LOGIN:
1280 return lastlog_perform_login(li);
1281 default:
1282 log("lastlog_write_entry: Invalid type field");
1283 return 0;
1284 }
andre61e67252000-06-04 17:07:49 +00001285}
andre2ff7b5d2000-06-03 14:57:40 +00001286
1287
1288static void
andre61e67252000-06-04 17:07:49 +00001289lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1290{
andre2ff7b5d2000-06-03 14:57:40 +00001291 line_fullname(li->line, last->ll_line, sizeof(li->line));
1292 strlcpy(li->hostname, last->ll_host, sizeof(li->hostname));
1293 li->tv_sec = last->ll_time;
andre61e67252000-06-04 17:07:49 +00001294}
andre2ff7b5d2000-06-03 14:57:40 +00001295
1296
1297int
andre61e67252000-06-04 17:07:49 +00001298lastlog_get_entry(struct logininfo *li)
1299{
andre2ff7b5d2000-06-03 14:57:40 +00001300 struct lastlog last;
1301 int fd;
1302
1303 if (lastlog_openseek(li, &fd, O_RDONLY)) {
1304 if ( read(fd, &last, sizeof(struct lastlog))
1305 != sizeof(struct lastlog) ) {
1306 log("lastlog_write_filemode: Error reading from %s: %s",
1307 LASTLOG_FILE, strerror(errno));
1308 return 0;
1309 } else {
1310 lastlog_populate_entry(li, &last);
1311 return 1;
1312 }
andre2ff7b5d2000-06-03 14:57:40 +00001313 } else
1314 return 0;
andre61e67252000-06-04 17:07:49 +00001315}
andre2ff7b5d2000-06-03 14:57:40 +00001316
1317
Damien Millerd5bf3072000-06-07 21:32:13 +10001318#endif /* USE_LASTLOG */