blob: ed14f3a74656ad0f0e5e587bb6197fef1f1d21e3 [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
159#include <sys/types.h>
160#include <sys/stat.h>
161#include <netinet/in.h>
162#include <unistd.h>
163#include <fcntl.h>
164#include <stdlib.h>
165#include <string.h>
166#include <stdio.h>
167#include <errno.h>
168#ifdef HAVE_PWD_H
andre61e67252000-06-04 17:07:49 +0000169# include <pwd.h>
andre2ff7b5d2000-06-03 14:57:40 +0000170#endif
171#ifdef HAVE_SYS_TIME_H
172# include <sys/time.h>
173#else
174# include <time.h>
175#endif
andre61e67252000-06-04 17:07:49 +0000176#if HAVE_UTMP_H
177# include <utmp.h>
178#endif
179#if HAVE_UTMPX_H
180# include <utmpx.h>
181#endif
182#if HAVE_LASTLOG_H
183# include <lastlog.h>
184#endif
andre2ff7b5d2000-06-03 14:57:40 +0000185
186#include "ssh.h"
187#include "xmalloc.h"
188#include "loginrec.h"
189
andre61e67252000-06-04 17:07:49 +0000190RCSID("$Id: loginrec.c,v 1.3 2000/06/04 17:07:49 andre Exp $");
andre2ff7b5d2000-06-03 14:57:40 +0000191
192
193/**
194 ** prototypes for helper functions in this file
195 **/
196
197#if HAVE_UTMP_H
andre2ff7b5d2000-06-03 14:57:40 +0000198void set_utmp_time(struct logininfo *li, struct utmp *ut);
199void construct_utmp(struct logininfo *li, struct utmp *ut);
200#endif
201
202#ifdef HAVE_UTMPX_H
andre2ff7b5d2000-06-03 14:57:40 +0000203void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
204void construct_utmpx(struct logininfo *li, struct utmpx *ut);
205#endif
206
207int utmp_write_entry(struct logininfo *li);
208int utmpx_write_entry(struct logininfo *li);
209int wtmp_write_entry(struct logininfo *li);
210int wtmpx_write_entry(struct logininfo *li);
211int lastlog_write_entry(struct logininfo *li);
212int syslogin_write_entry(struct logininfo *li);
213
214int getlast_entry(struct logininfo *li);
215int lastlog_get_entry(struct logininfo *li);
216int wtmp_get_entry(struct logininfo *li);
217int wtmpx_get_entry(struct logininfo *li);
218
219
220/**
221 ** platform-independent login functions
222 **/
223
andre61e67252000-06-04 17:07:49 +0000224/* Record a login */
225int
226login_login (struct logininfo *li)
227{
228 li->type = LTYPE_LOGIN;
229 return login_write(li);
230}
231
232
233/* Record a logout */
234int
235login_logout(struct logininfo *li)
236{
237 li->type = LTYPE_LOGOUT;
238 return login_write(li);
239}
240
241
242/* Retrieve the last login time for a user (or fake on from wtmp/wtmpx) */
243unsigned int
244login_get_lastlog_time(const int uid)
245{
246 struct logininfo li;
247
248 login_get_lastlog(&li, uid);
249 return li.tv_sec;
250}
251
252/* Retrieve a lastlog entry (or fake one from wtmp/wtmpx) */
253struct logininfo *
254login_get_lastlog(struct logininfo *li, const int uid)
255{
256 memset(li, '\0', sizeof(struct logininfo));
257 li->uid = uid;
258 if (getlast_entry(li))
259 return li;
260 else
261 return 0;
262}
263
264
andre2ff7b5d2000-06-03 14:57:40 +0000265/* login_alloc_entry() - allocate and initialise a logininfo */
andre61e67252000-06-04 17:07:49 +0000266struct
267logininfo *login_alloc_entry(int pid, const char *username,
268 const char *hostname, const char *line)
269{
andre2ff7b5d2000-06-03 14:57:40 +0000270 struct logininfo *newli;
271
272 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo));
andre61e67252000-06-04 17:07:49 +0000273 (void)login_init_entry(newli, pid, username, hostname, line);
274 return newli;
275}
andre2ff7b5d2000-06-03 14:57:40 +0000276
277
andre61e67252000-06-04 17:07:49 +0000278/* login_free_entry() - free struct memory (trivial) */
279void
280login_free_entry(struct logininfo *li)
281{
282 xfree(li);
283}
284
andre2ff7b5d2000-06-03 14:57:40 +0000285
286/* login_init_entry() - initialise a struct logininfo */
andre61e67252000-06-04 17:07:49 +0000287int
288login_init_entry(struct logininfo *li, int pid, const char *username,
289 const char *hostname, const char *line)
290{
andre2ff7b5d2000-06-03 14:57:40 +0000291 /* zero the structure */
292 memset(li, 0, sizeof(struct logininfo));
293
andre61e67252000-06-04 17:07:49 +0000294 li->pid = pid;
andre2ff7b5d2000-06-03 14:57:40 +0000295 /* set the line information */
andre61e67252000-06-04 17:07:49 +0000296 if (line)
andre2ff7b5d2000-06-03 14:57:40 +0000297 line_fullname(li->line, line, sizeof(li->line));
andre2ff7b5d2000-06-03 14:57:40 +0000298
andre61e67252000-06-04 17:07:49 +0000299 if (username)
andre2ff7b5d2000-06-03 14:57:40 +0000300 strlcpy(li->username, username, sizeof(li->username));
andre61e67252000-06-04 17:07:49 +0000301 if (hostname)
andre2ff7b5d2000-06-03 14:57:40 +0000302 strlcpy(li->hostname, hostname, sizeof(li->hostname));
andre61e67252000-06-04 17:07:49 +0000303 return 1;
andre2ff7b5d2000-06-03 14:57:40 +0000304}
305
306
307void
andre61e67252000-06-04 17:07:49 +0000308login_set_current_time(struct logininfo *li)
309{
andre2ff7b5d2000-06-03 14:57:40 +0000310#ifdef HAVE_SYS_TIME_H
311 struct timeval tv;
312
313 gettimeofday(&tv, NULL);
314 li->tv_sec = tv.tv_sec ; li->tv_usec = tv.tv_usec;
315#else
andre61e67252000-06-04 17:07:49 +0000316 time_t tm = time(0);
317
318 li->tv_sec = tm; li->tv_usec = 0;
andre2ff7b5d2000-06-03 14:57:40 +0000319#endif
320}
321
andre61e67252000-06-04 17:07:49 +0000322
323/* copy a sockaddr_* into our logininfo */
andre2ff7b5d2000-06-03 14:57:40 +0000324void
andre61e67252000-06-04 17:07:49 +0000325login_set_addr(struct logininfo *li, const struct sockaddr *sa,
326 const unsigned int sa_size)
327{
328 unsigned int bufsize = sa_size;
329
330 /* make sure we don't overrun our union */
331 if (sizeof(li->hostaddr) < sa_size)
332 bufsize = sizeof(li->hostaddr);
333
334 memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
andre2ff7b5d2000-06-03 14:57:40 +0000335}
336
andre2ff7b5d2000-06-03 14:57:40 +0000337
andre61e67252000-06-04 17:07:49 +0000338/**
339 ** login_write: Call low-level recording functions based on autoconf
340 ** results
341 **/
andre2ff7b5d2000-06-03 14:57:40 +0000342
343int
andre61e67252000-06-04 17:07:49 +0000344login_write (struct logininfo *li)
345{
andre2ff7b5d2000-06-03 14:57:40 +0000346 if ((int)geteuid() != 0) {
347 log("Attempt to write login records by non-root user (aborting)");
348 return 1;
349 }
350 /* set the timestamp */
351 login_set_current_time(li);
352#ifdef USE_LOGIN
353 syslogin_write_entry(li);
354#endif
355#ifdef USE_LASTLOG
356 if (li->type == LTYPE_LOGIN) {
357 lastlog_write_entry(li);
358 }
359#endif
360#ifdef USE_UTMP
361 utmp_write_entry(li);
362#endif
363#ifdef USE_WTMP
364 wtmp_write_entry(li);
365#endif
366#ifdef USE_UTMPX
367 utmpx_write_entry(li);
368#endif
369#ifdef USE_WTMPX
370 wtmpx_write_entry(li);
371#endif
372 return 0;
373}
374
andre2ff7b5d2000-06-03 14:57:40 +0000375
376/**
andre61e67252000-06-04 17:07:49 +0000377 ** getlast_entry: Call low-level functions to retrieve the last login
378 ** time.
andre2ff7b5d2000-06-03 14:57:40 +0000379 **/
380
andre61e67252000-06-04 17:07:49 +0000381/* take the uid in li and return the last login time */
382int
383getlast_entry(struct logininfo *li)
384{
385#ifdef USE_LASTLOG
386 if (lastlog_get_entry(li))
387 return 1;
388 else
389 return 0;
390#else
391 /* !USE_LASTLOG */
392
393 /* Try to retrieve the last login time from wtmp */
394# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
395 /* retrieve last login time from utmp */
396 if (wtmp_get_entry(li))
397 return 1;
398 else
399 return 0;
400# else
401
402 /* If wtmp isn't available, try wtmpx */
403
404# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
405 /* retrieve last login time from utmpx */
406 if (wtmpx_get_entry(li))
407 return 1;
408 else
409 return 0;
410# else
411
412 /* Give up: No means of retrieving last login time */
413 return 0;
414# endif
415# endif
416#endif
417/* USE_LASTLOG */
418}
419
420
421
andre2ff7b5d2000-06-03 14:57:40 +0000422/*
andre61e67252000-06-04 17:07:49 +0000423 * 'line' string utility functions
424 *
425 * These functions process the 'line' string into one of three forms:
426 *
andre2ff7b5d2000-06-03 14:57:40 +0000427 * 1. The full filename (including '/dev')
428 * 2. The stripped name (excluding '/dev')
andre61e67252000-06-04 17:07:49 +0000429 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
430 * /dev/pts/1 -> ts/1 )
andre2ff7b5d2000-06-03 14:57:40 +0000431 *
432 * Form 3 is used on some systems to identify a .tmp.? entry when
433 * attempting to remove it. Typically both addition and removal is
andre61e67252000-06-04 17:07:49 +0000434 * performed by one application - say, sshd - so as long as the choice
435 * uniquely identifies a terminal it's ok.
andre2ff7b5d2000-06-03 14:57:40 +0000436 */
437
438
andre61e67252000-06-04 17:07:49 +0000439/* line_fullname(): add the leading '/dev/' if it doesn't exist make
440 * sure dst has enough space, if not just copy src (ugh) */
andre2ff7b5d2000-06-03 14:57:40 +0000441char *
andre61e67252000-06-04 17:07:49 +0000442line_fullname(char *dst, const char *src, int dstsize)
443{
andre2ff7b5d2000-06-03 14:57:40 +0000444 memset(dst, '\0', dstsize);
445 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
446 strlcpy(dst, src, dstsize);
447 else {
448 strlcpy(dst, "/dev/", 5);
449 strlcat(dst, src, dstsize);
450 }
451 return dst;
452}
453
andre61e67252000-06-04 17:07:49 +0000454
455/* line_stripname(): strip the leading '/dev' if it exists, return dst */
andre2ff7b5d2000-06-03 14:57:40 +0000456char *
andre61e67252000-06-04 17:07:49 +0000457line_stripname(char *dst, const char *src, int dstsize)
458{
andre2ff7b5d2000-06-03 14:57:40 +0000459 memset(dst, '\0', dstsize);
460 if (strncmp(src, "/dev/", 5) == 0)
461 strlcpy(dst, &src[5], dstsize);
462 else
463 strlcpy(dst, src, dstsize);
464 return dst;
andre61e67252000-06-04 17:07:49 +0000465}
466
andre2ff7b5d2000-06-03 14:57:40 +0000467
andre61e67252000-06-04 17:07:49 +0000468/* line_abbrevname(): Return the abbreviated (usually four-character)
469 * form of the line (Just use the last <dstsize> characters of the
470 * full name.)
471 *
472 * NOTE: use strncpy because we do NOT necessarily want zero
473 * termination */
andre2ff7b5d2000-06-03 14:57:40 +0000474char *
475line_abbrevname(char *dst, const char *src, int dstsize) {
476 memset(dst, '\0', dstsize);
andre61e67252000-06-04 17:07:49 +0000477 src += (strlen(src) - dstsize);
478 strncpy(dst, src, dstsize); /* note: _don't_ change this to strlcpy */
andre2ff7b5d2000-06-03 14:57:40 +0000479 return dst;
480}
481
482
483/**
484 ** utmp utility functions
andre61e67252000-06-04 17:07:49 +0000485 **
486 ** These functions manipulate struct utmp, taking system differences
487 ** into account.
andre2ff7b5d2000-06-03 14:57:40 +0000488 **/
489
490#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
491
andre2ff7b5d2000-06-03 14:57:40 +0000492/* build the utmp structure */
493void
andre61e67252000-06-04 17:07:49 +0000494set_utmp_time(struct logininfo *li, struct utmp *ut)
495{
andre2ff7b5d2000-06-03 14:57:40 +0000496#ifdef HAVE_TV_IN_UTMP
497 ut->ut_tv.tv_sec = li->tv_sec;
498 ut->ut_tv.tv_usec = li->tv_usec;
499#else
500# ifdef HAVE_TIME_IN_UTMP
501 ut->ut_time = li->tv_sec;
502# endif
503#endif
504}
505
andre61e67252000-06-04 17:07:49 +0000506
andre2ff7b5d2000-06-03 14:57:40 +0000507void
508construct_utmp(struct logininfo *li,
andre61e67252000-06-04 17:07:49 +0000509 struct utmp *ut)
510{
andre2ff7b5d2000-06-03 14:57:40 +0000511 memset(ut, '\0', sizeof(struct utmp));
andre2ff7b5d2000-06-03 14:57:40 +0000512#ifdef HAVE_ID_IN_UTMP
513 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
514#endif
515
516#ifdef HAVE_TYPE_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000517 /* This is done here to keep utmp constants out of login.h */
andre2ff7b5d2000-06-03 14:57:40 +0000518 switch (li->type) {
519 case LTYPE_LOGIN:
520 ut->ut_type = USER_PROCESS;
521 break;
522 case LTYPE_LOGOUT:
523 ut->ut_type = DEAD_PROCESS;
524 break;
525 }
526#endif
527
528#ifdef HAVE_PID_IN_UTMP
529 ut->ut_pid = li->pid;
530#endif
531 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
532 strlcpy(ut->ut_name, li->username, sizeof(ut->ut_name));
533 set_utmp_time(li, ut);
534#ifdef HAVE_HOST_IN_UTMP
535 strlcpy(ut->ut_host, li->hostname, sizeof(ut->ut_host));
536#endif
537#ifdef HAVE_ADDR_IN_UTMP
andre61e67252000-06-04 17:07:49 +0000538 /* this is just a 32-bit IP address */
539 if (li->hostaddr.sa.sa_family == AF_INET)
540 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
541#endif
542}
andre2ff7b5d2000-06-03 14:57:40 +0000543
544#endif
545/* USE_UTMP || USE_WTMP || USE_LOGIN */
546
andre61e67252000-06-04 17:07:49 +0000547
548
andre2ff7b5d2000-06-03 14:57:40 +0000549/**
550 ** utmpx utility functions
andre61e67252000-06-04 17:07:49 +0000551 **
552 ** These functions manipulate struct utmpx, accounting for system
553 ** variations.
andre2ff7b5d2000-06-03 14:57:40 +0000554 **/
555
556#if defined(USE_UTMPX) || defined (USE_WTMPX)
557
andre2ff7b5d2000-06-03 14:57:40 +0000558/* build the utmpx structure */
559void
andre61e67252000-06-04 17:07:49 +0000560set_utmpx_time(struct logininfo *li, struct utmpx *utx)
561{
andre2ff7b5d2000-06-03 14:57:40 +0000562#ifdef HAVE_TV_IN_UTMPX
563 utx->ut_tv.tv_sec = li->tv_sec;
564 utx->ut_tv.tv_usec = li->tv_usec;
565#else
566# ifdef HAVE_TIME_IN_UTMPX
567 utx->ut_time = li->tv_sec;
568# endif
569#endif
570}
571
andre2ff7b5d2000-06-03 14:57:40 +0000572
andre61e67252000-06-04 17:07:49 +0000573void
574construct_utmpx(struct logininfo *li, struct utmpx *utx)
575{
576 memset(utx, '\0', sizeof(struct utmpx));
andre2ff7b5d2000-06-03 14:57:40 +0000577 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
578
579 /* this is done here to keep utmp constants out of loginrec.h */
580 switch (li->type) {
581 case LTYPE_LOGIN:
582 utx->ut_type = USER_PROCESS;
583 break;
584 case LTYPE_LOGOUT:
585 utx->ut_type = DEAD_PROCESS;
586 break;
587 }
andre2ff7b5d2000-06-03 14:57:40 +0000588 utx->ut_pid = li->pid;
589 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
590 strlcpy(utx->ut_name, li->username, sizeof(utx->ut_name));
591 set_utmpx_time(li, utx);
592#ifdef HAVE_HOST_IN_UTMPX
593 strlcpy(utx->ut_host, li->hostname, sizeof(utx->ut_host));
594#endif
595#ifdef HAVE_ADDR_IN_UTMPX
andre61e67252000-06-04 17:07:49 +0000596 /* FIXME: (ATL) not supported yet */
andre2ff7b5d2000-06-03 14:57:40 +0000597#endif
598#ifdef HAVE_SYSLEN_IN_UTMPX
599 /* this is safe because of the extra nulls in logininfo */
600 utx->ut_syslen = strlen(li->hostname);
601#endif
andre61e67252000-06-04 17:07:49 +0000602}
andre2ff7b5d2000-06-03 14:57:40 +0000603
604#endif
605/* USE_UTMPX || USE_WTMPX */
606
607
608
609/**
andre61e67252000-06-04 17:07:49 +0000610 ** Low-level utmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000611 **/
612
613/* FIXME: (ATL) utmp_write_direct needs testing */
614
615#ifdef USE_UTMP
616
andre2ff7b5d2000-06-03 14:57:40 +0000617/* if we can, use pututline() etc. */
618#if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
619 defined(HAVE_PUTUTLINE)
620# define UTMP_USE_LIBRARY
621#endif
622
623
624/* write a utmp entry with the system's help (pututline() and pals) */
625#ifdef UTMP_USE_LIBRARY
626static int
andre61e67252000-06-04 17:07:49 +0000627utmp_write_library(struct logininfo *li, struct utmp *ut)
628{
andre2ff7b5d2000-06-03 14:57:40 +0000629 setutent();
630 pututline(ut);
631
632#ifdef HAVE_ENDUTENT
633 endutent();
634#endif
635 return 1;
andre61e67252000-06-04 17:07:49 +0000636}
andre2ff7b5d2000-06-03 14:57:40 +0000637
638#else
639
640/* write a utmp entry direct to the file */
andre61e67252000-06-04 17:07:49 +0000641/* This is a slightly modification of code in OpenBSD's login.c */
andre2ff7b5d2000-06-03 14:57:40 +0000642static int
andre61e67252000-06-04 17:07:49 +0000643utmp_write_direct(struct logininfo *li, struct utmp *ut)
644{
andre2ff7b5d2000-06-03 14:57:40 +0000645 struct utmp old_ut;
646 register int fd;
647 int tty;
648
649 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
650
651 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
652 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
653 /*
654 * Prevent luser from zero'ing out ut_host.
655 * If the new ut_line is empty but the old one is not
656 * and ut_line and ut_name match, preserve the old ut_line.
657 */
658 if ( read(fd, &old_ut, sizeof(struct utmp)) == sizeof(struct utmp)
659 && ut->ut_host[0] == '\0'
660 && old_ut.ut_host[0] != '\0'
661 && strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0
662 && strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0 )
663 (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
664
665 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
666 if (write(fd, ut, sizeof(struct utmp))==-1)
667 log("utmp_write_direct: error writing %s: %s",
668 UTMP_FILE, strerror(errno));
669
670 (void)close(fd);
671 return 1;
672 } else
673 return 0;
andre61e67252000-06-04 17:07:49 +0000674}
andre2ff7b5d2000-06-03 14:57:40 +0000675#endif /* UTMP_USE_LIBRARY */
676
677
678static int
andre61e67252000-06-04 17:07:49 +0000679utmp_perform_login(struct logininfo *li)
680{
andre2ff7b5d2000-06-03 14:57:40 +0000681 struct utmp ut;
682
683 construct_utmp(li, &ut);
andre2ff7b5d2000-06-03 14:57:40 +0000684#ifdef UTMP_USE_LIBRARY
685 if (!utmp_write_library(li, &ut)) {
686 log("utmp_perform_login: utmp_write_library() failed");
687 return 0;
688 }
689#else
690 if (!utmp_write_direct(li, &ut)) {
691 log("utmp_perform_login: utmp_write_direct() failed");
692 return 0;
693 }
694#endif
695 return 1;
andre61e67252000-06-04 17:07:49 +0000696}
andre2ff7b5d2000-06-03 14:57:40 +0000697
698
699static int
andre61e67252000-06-04 17:07:49 +0000700utmp_perform_logout(struct logininfo *li)
701{
andre2ff7b5d2000-06-03 14:57:40 +0000702 struct utmp ut;
703
704 memset(&ut, '\0', sizeof(ut));
705 set_utmp_time(li, &ut);
706 line_stripname(ut.ut_line, li->line, sizeof(ut.ut_line));
707#ifdef HAVE_ID_IN_UTMP
708 line_abbrevname(ut.ut_id, li->line, sizeof(ut.ut_id));
709#endif
710#ifdef HAVE_TYPE_IN_UTMP
711 ut.ut_type = DEAD_PROCESS;
712#endif
713
714#if !defined(DISABLE_PUTUTLINE) \
715 && defined(HAVE_SETUTENT) && defined(HAVE_PUTUTLINE)
716 utmp_write_library(li, &ut);
717#else
718 utmp_write_direct(li, &ut);
719#endif
720
721 return 1;
andre61e67252000-06-04 17:07:49 +0000722}
andre2ff7b5d2000-06-03 14:57:40 +0000723
724
725int
andre61e67252000-06-04 17:07:49 +0000726utmp_write_entry(struct logininfo *li)
727{
andre2ff7b5d2000-06-03 14:57:40 +0000728 switch(li->type) {
729 case LTYPE_LOGIN:
730 return utmp_perform_login(li);
731
732 case LTYPE_LOGOUT:
733 return utmp_perform_logout(li);
734
735 default:
736 log("utmp_write_entry: invalid type field");
737 return 0;
738 }
andre61e67252000-06-04 17:07:49 +0000739}
andre2ff7b5d2000-06-03 14:57:40 +0000740
741
742#endif
743/* USE_UTMP */
744
745
746/**
andre61e67252000-06-04 17:07:49 +0000747 ** Low-level utmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000748 **/
749
750/* not much point if we don't want utmpx entries */
751#ifdef USE_UTMPX
752
andre2ff7b5d2000-06-03 14:57:40 +0000753/* if we have the wherewithall, use pututxline etc. */
754#if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) \
755 && defined(HAVE_PUTUTXLINE)
756# define UTMPX_USE_LIBRARY
757#endif
758
759
760/* write a utmpx entry with the system's help (pututxline() and pals) */
761#ifdef UTMPX_USE_LIBRARY
762static int
andre61e67252000-06-04 17:07:49 +0000763utmpx_write_library(struct logininfo *li, struct utmpx *utx)
764{
andre2ff7b5d2000-06-03 14:57:40 +0000765 setutxent();
766 pututxline(utx);
767
768#ifdef HAVE_ENDUTXENT
769 endutxent();
770#endif
771 return 1;
andre61e67252000-06-04 17:07:49 +0000772}
andre2ff7b5d2000-06-03 14:57:40 +0000773
774#else
775/* UTMPX_USE_LIBRARY */
776
777
778/* write a utmp entry direct to the file */
779static int
andre61e67252000-06-04 17:07:49 +0000780utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
781{
andre2ff7b5d2000-06-03 14:57:40 +0000782 log("utmpx_write_direct: not implemented!");
783 return 0;
andre61e67252000-06-04 17:07:49 +0000784}
andre2ff7b5d2000-06-03 14:57:40 +0000785
786#endif
787/* UTMPX_USE_LIBRARY */
788
789static int
andre61e67252000-06-04 17:07:49 +0000790utmpx_perform_login(struct logininfo *li)
791{
andre2ff7b5d2000-06-03 14:57:40 +0000792 struct utmpx utx;
793
794 construct_utmpx(li, &utx);
andre2ff7b5d2000-06-03 14:57:40 +0000795#ifdef UTMPX_USE_LIBRARY
796 if (!utmpx_write_library(li, &utx)) {
797 log("utmpx_perform_login: utmp_write_library() failed");
798 return 0;
799 }
800#else
801 if (!utmpx_write_direct(li, &ut)) {
802 log("utmpx_perform_login: utmp_write_direct() failed");
803 return 0;
804 }
805#endif
806 return 1;
andre61e67252000-06-04 17:07:49 +0000807}
andre2ff7b5d2000-06-03 14:57:40 +0000808
809
810static int
andre61e67252000-06-04 17:07:49 +0000811utmpx_perform_logout(struct logininfo *li)
812{
andre2ff7b5d2000-06-03 14:57:40 +0000813 struct utmpx utx;
814
815 memset(&utx, '\0', sizeof(utx));
816 set_utmpx_time(li, &utx);
817 line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
818#ifdef HAVE_ID_IN_UTMPX
819 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
820#endif
821#ifdef HAVE_TYPE_IN_UTMPX
822 utx.ut_type = DEAD_PROCESS;
823#endif
824
825#ifdef UTMPX_USE_LIBRARY
826 utmpx_write_library(li, &utx);
827#else
828 utmpx_write_direct(li, &utx);
829#endif
andre2ff7b5d2000-06-03 14:57:40 +0000830 return 1;
andre61e67252000-06-04 17:07:49 +0000831}
andre2ff7b5d2000-06-03 14:57:40 +0000832
833
834int
andre61e67252000-06-04 17:07:49 +0000835utmpx_write_entry(struct logininfo *li)
836{
andre2ff7b5d2000-06-03 14:57:40 +0000837 switch(li->type) {
838 case LTYPE_LOGIN:
839 return utmpx_perform_login(li);
840 case LTYPE_LOGOUT:
841 return utmpx_perform_logout(li);
842 default:
843 log("utmpx_write_entry: invalid type field");
844 return 0;
845 }
andre61e67252000-06-04 17:07:49 +0000846}
andre2ff7b5d2000-06-03 14:57:40 +0000847
848
849#endif
850/* USE_UTMPX */
851
852
853/**
andre61e67252000-06-04 17:07:49 +0000854 ** Low-level wtmp functions
andre2ff7b5d2000-06-03 14:57:40 +0000855 **/
856
857#ifdef USE_WTMP
858
andre2ff7b5d2000-06-03 14:57:40 +0000859/* write a wtmp entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000860/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000861static int
andre61e67252000-06-04 17:07:49 +0000862wtmp_write(struct logininfo *li, struct utmp *ut)
863{
andre2ff7b5d2000-06-03 14:57:40 +0000864 struct stat buf;
865 int fd, ret = 1;
866
867 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
868 log("wtmp_write: problem writing %s: %s",
869 WTMP_FILE, strerror(errno));
870 return 0;
871 }
andre61e67252000-06-04 17:07:49 +0000872 if (fstat(fd, &buf) == 0)
andre2ff7b5d2000-06-03 14:57:40 +0000873 if (write(fd, (char *)ut, sizeof(struct utmp)) !=
874 sizeof(struct utmp)) {
875 ftruncate(fd, buf.st_size);
876 log("wtmp_write: problem writing %s: %s",
877 WTMP_FILE, strerror(errno));
878 ret = 0;
879 }
880 (void)close(fd);
andre2ff7b5d2000-06-03 14:57:40 +0000881 return ret;
andre61e67252000-06-04 17:07:49 +0000882}
andre2ff7b5d2000-06-03 14:57:40 +0000883
884
885static int
andre61e67252000-06-04 17:07:49 +0000886wtmp_perform_login(struct logininfo *li){
andre2ff7b5d2000-06-03 14:57:40 +0000887 struct utmp ut;
888
889 construct_utmp(li, &ut);
890 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000891}
andre2ff7b5d2000-06-03 14:57:40 +0000892
893
894static int
andre61e67252000-06-04 17:07:49 +0000895wtmp_perform_logout(struct logininfo *li)
896{
andre2ff7b5d2000-06-03 14:57:40 +0000897 struct utmp ut;
898
899 construct_utmp(li, &ut);
900 /* blank out unnecessary fields */
901 memset(&(ut.ut_name), '\0', sizeof(ut.ut_name));
902#ifdef HAVE_ID_IN_UTMP
903 memset(&(ut.ut_id), '\0', sizeof(ut.ut_id));
904#endif
905#ifdef HAVE_HOST_IN_UTMP
906 memset(&(ut.ut_host), '\0', sizeof(ut.ut_host));
907#endif
908#ifdef HAVE_ADDR_IN_UTMP
909 memset(&(ut.ut_addr), '\0', sizeof(ut.ut_addr));
910#endif
911 return wtmp_write(li, &ut);
andre61e67252000-06-04 17:07:49 +0000912}
andre2ff7b5d2000-06-03 14:57:40 +0000913
914
915int
andre61e67252000-06-04 17:07:49 +0000916wtmp_write_entry(struct logininfo *li)
917{
andre2ff7b5d2000-06-03 14:57:40 +0000918 switch(li->type) {
919 case LTYPE_LOGIN:
920 return wtmp_perform_login(li);
921 case LTYPE_LOGOUT:
922 return wtmp_perform_logout(li);
923 default:
924 log("wtmp_write_entry: invalid type field");
925 return 0;
926 }
andre61e67252000-06-04 17:07:49 +0000927}
andre2ff7b5d2000-06-03 14:57:40 +0000928
929
930int
andre61e67252000-06-04 17:07:49 +0000931wtmp_get_entry(struct logininfo *li)
932{
andre2ff7b5d2000-06-03 14:57:40 +0000933 struct stat st;
934 struct utmp ut;
935 int fd;
936
937 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
938 log("wtmp_get_entry: problem opening %s: %s",
939 WTMP_FILE, strerror(errno));
940 return 0;
941 }
andre61e67252000-06-04 17:07:49 +0000942 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +0000943 log("wtmp_get_entry: couldn't stat %s: %s",
944 WTMP_FILE, strerror(errno));
945 close(fd);
946 return 0;
947 }
andre2ff7b5d2000-06-03 14:57:40 +0000948 (void)lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END);
949
950 do {
951 if (read(fd, &ut, sizeof(ut)) != sizeof(ut)) {
952 log("wtmp_get_entry: read of %s failed: %s",
953 WTMP_FILE, strerror(errno));
954 close (fd);
955 return 0;
956 }
andre2ff7b5d2000-06-03 14:57:40 +0000957 /* Logouts are recorded as a blank username on a particular line.
958 * So, we just need to find the username in struct utmp */
959 if ( strncmp(li->username, ut.ut_user, 8) == 0 ) {
960 /* note we've already made sure there's a time in struct utmp */
961#ifdef HAVE_TIME_IN_UTMP
962 li->tv_sec = ut.ut_time;
963#else
964# if HAVE_TV_IN_UTMP
965 li->tv_sec = ut.ut_tv.tv_sec;
966# endif
967#endif
968 line_fullname(li->line, ut.ut_line, sizeof(ut.ut_line));
969#ifdef HAVE_HOST_IN_UTMP
970 strlcpy(li->hostname, ut.ut_host, sizeof(ut.ut_host));
971#endif
972 }
973 if (lseek(fd, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1) {
974 close (fd);
975 return 0;
976 }
977 } while (li->tv_sec == 0);
978
979 return 1;
andre61e67252000-06-04 17:07:49 +0000980}
andre2ff7b5d2000-06-03 14:57:40 +0000981
982
983#endif
984/* USE_WTMP */
985
986
987/**
andre61e67252000-06-04 17:07:49 +0000988 ** Low-level wtmpx functions
andre2ff7b5d2000-06-03 14:57:40 +0000989 **/
990
991#ifdef USE_WTMPX
992
andre2ff7b5d2000-06-03 14:57:40 +0000993/* write a wtmpx entry direct to the end of the file */
andre61e67252000-06-04 17:07:49 +0000994/* This is a slight modification of code in OpenBSD's logwtmp.c */
andre2ff7b5d2000-06-03 14:57:40 +0000995static int
andre61e67252000-06-04 17:07:49 +0000996wtmpx_write(struct logininfo *li, struct utmpx *utx)
997{
andre2ff7b5d2000-06-03 14:57:40 +0000998 struct stat buf;
999 int fd, ret = 1;
1000
1001 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1002 log("wtmpx_write: problem opening %s: %s",
1003 WTMPX_FILE, strerror(errno));
1004 return 0;
1005 }
1006
1007 if (fstat(fd, &buf) == 0)
1008 if (write(fd, (char *)utx, sizeof(struct utmpx)) !=
1009 sizeof(struct utmpx)) {
1010 ftruncate(fd, buf.st_size);
1011 log("wtmpx_write: problem writing %s: %s",
1012 WTMPX_FILE, strerror(errno));
1013 ret = 0;
1014 }
1015 (void)close(fd);
1016
1017 return ret;
andre61e67252000-06-04 17:07:49 +00001018}
andre2ff7b5d2000-06-03 14:57:40 +00001019
1020
1021static int
andre61e67252000-06-04 17:07:49 +00001022wtmpx_perform_login(struct logininfo *li)
1023{
andre2ff7b5d2000-06-03 14:57:40 +00001024 struct utmpx utx;
1025
1026 construct_utmpx(li, &utx);
1027 return wtmpx_write(li, &utx);
andre61e67252000-06-04 17:07:49 +00001028}
andre2ff7b5d2000-06-03 14:57:40 +00001029
1030
1031static int
andre61e67252000-06-04 17:07:49 +00001032wtmpx_perform_logout(struct logininfo *li)
1033{
andre2ff7b5d2000-06-03 14:57:40 +00001034 struct utmpx utx;
1035
1036 construct_utmpx(li, &utx);
1037 /* blank out unnecessary fields */
1038 memset(&(utx.ut_name), '\0', sizeof(utx.ut_name));
1039#ifdef HAVE_ID_IN_UTMPX
1040 memset(&(utx.ut_id), '\0', sizeof(utx.ut_id));
1041#endif
1042#ifdef HAVE_HOST_IN_UTMPX
1043 memset(&(utx.ut_host), '\0', sizeof(utx.ut_host));
1044#endif
1045#ifdef HAVE_ADDR_IN_UTMPX
1046 memset(&(utx.ut_addr), '\0', sizeof(utx.ut_addr));
1047#endif
1048 return wtmpx_write(li, &utx);
1049
andre61e67252000-06-04 17:07:49 +00001050}
andre2ff7b5d2000-06-03 14:57:40 +00001051
1052
1053int
andre61e67252000-06-04 17:07:49 +00001054wtmpx_write_entry(struct logininfo *li)
1055{
andre2ff7b5d2000-06-03 14:57:40 +00001056 switch(li->type) {
1057 case LTYPE_LOGIN:
1058 return wtmpx_perform_login(li);
1059 case LTYPE_LOGOUT:
1060 return wtmpx_perform_logout(li);
1061 default:
1062 log("wtmpx_write_entry: invalid type field");
1063 return 0;
1064 }
andre61e67252000-06-04 17:07:49 +00001065}
andre2ff7b5d2000-06-03 14:57:40 +00001066
1067
1068int
andre61e67252000-06-04 17:07:49 +00001069wtmpx_get_entry(struct logininfo *li)
1070{
andre2ff7b5d2000-06-03 14:57:40 +00001071 struct stat st;
1072 struct utmpx utx;
1073 int fd;
1074
1075 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1076 log("wtmpx_get_entry: problem opening %s: %s",
1077 WTMPX_FILE, strerror(errno));
1078 return 0;
1079 }
andre61e67252000-06-04 17:07:49 +00001080 if (fstat(fd, &st) != 0) {
andre2ff7b5d2000-06-03 14:57:40 +00001081 log("wtmpx_get_entry: couldn't stat %s: %s",
1082 WTMP_FILE, strerror(errno));
1083 close(fd);
1084 return 0;
1085 }
andre2ff7b5d2000-06-03 14:57:40 +00001086 (void)lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END);
1087
1088 do {
1089 if (read(fd, &utx, sizeof(utx)) != sizeof(utx)) {
1090 log("wtmpx_get_entry: read of %s failed: %s",
1091 WTMPX_FILE, strerror(errno));
1092 close (fd);
1093 return 0;
1094 }
andre2ff7b5d2000-06-03 14:57:40 +00001095 /* Logouts are recorded as a blank username on a particular line.
1096 * So, we just need to find the username in struct utmpx */
1097 if ( strncmp(li->username, utx.ut_user, 8) == 0 ) {
1098 /* note we've already made sure there's a time in struct utmp */
1099#ifdef HAVE_TV_IN_UTMPX
1100 li->tv_sec = utx.ut_tv.tv_sec;
1101#else
1102# ifdef HAVE_TIME_IN_UTMPX
1103 li->tv_sec = utx.ut_time;
1104# endif
1105#endif
1106 line_fullname(li->line, utx.ut_line, sizeof(utx.ut_line));
1107#ifdef HAVE_HOST_IN_UTMPX
1108 strlcpy(li->hostname, utx.ut_host, sizeof(utx.ut_line));
1109#endif
1110 }
1111 if (lseek(fd, (off_t)(0-2*sizeof(struct utmpx)), SEEK_CUR) == -1) {
1112 close (fd);
1113 return 0;
1114 }
1115 } while (li->tv_sec == 0);
1116 return 1;
andre61e67252000-06-04 17:07:49 +00001117}
andre2ff7b5d2000-06-03 14:57:40 +00001118
1119
1120#endif
1121/* USE_WTMPX */
1122
1123
1124
1125/**
andre61e67252000-06-04 17:07:49 +00001126 ** Low-level libutil login() functions
andre2ff7b5d2000-06-03 14:57:40 +00001127 **/
1128
1129#ifdef USE_LOGIN
1130
andre2ff7b5d2000-06-03 14:57:40 +00001131static int
andre61e67252000-06-04 17:07:49 +00001132syslogin_perform_login(struct logininfo *li)
1133{
andre2ff7b5d2000-06-03 14:57:40 +00001134 struct utmp *ut;
1135
1136 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) {
1137 log("syslogin_perform_login: couldn't malloc()");
1138 return 0;
1139 }
1140 construct_utmp(li, ut);
1141 login(ut);
1142
1143 return 1;
andre61e67252000-06-04 17:07:49 +00001144}
1145
andre2ff7b5d2000-06-03 14:57:40 +00001146
1147static int
andre61e67252000-06-04 17:07:49 +00001148syslogin_perform_logout(struct logininfo *li)
1149{
andre2ff7b5d2000-06-03 14:57:40 +00001150#ifdef HAVE_LOGOUT
1151 char line[8];
1152
1153 (void)line_stripname(line, li->line, sizeof(line));
1154
1155 if (!logout(line)) {
1156 log("syslogin_perform_logout: logout() returned an error");
1157# ifdef HAVE_LOGWTMP
1158 } else {
1159 logwtmp(line, "", "");
1160 }
1161# endif
1162 /* TODO: what to do if we have login, but no logout?
1163 * what if logout but no logwtmp? All routines are in libutil
1164 * so they should all be there, but... */
1165#endif
1166 return 1;
andre61e67252000-06-04 17:07:49 +00001167}
andre2ff7b5d2000-06-03 14:57:40 +00001168
1169
1170int
andre61e67252000-06-04 17:07:49 +00001171syslogin_write_entry(struct logininfo *li)
1172{
andre2ff7b5d2000-06-03 14:57:40 +00001173 switch (li->type) {
1174 case LTYPE_LOGIN:
1175 return syslogin_perform_login(li);
1176 case LTYPE_LOGOUT:
1177 return syslogin_perform_logout(li);
1178 default:
1179 log("syslogin_write_entry: Invalid type field");
1180 return 0;
1181 }
andre61e67252000-06-04 17:07:49 +00001182}
andre2ff7b5d2000-06-03 14:57:40 +00001183
1184
1185#endif
1186/* USE_LOGIN */
1187
1188/* end of file log-syslogin.c */
1189
1190
1191/**
andre61e67252000-06-04 17:07:49 +00001192 ** Low-level lastlog functions
andre2ff7b5d2000-06-03 14:57:40 +00001193 **/
1194
1195#ifdef USE_LASTLOG
1196
andre2ff7b5d2000-06-03 14:57:40 +00001197static void
andre61e67252000-06-04 17:07:49 +00001198lastlog_construct(struct logininfo *li, struct lastlog *last)
1199{
andre2ff7b5d2000-06-03 14:57:40 +00001200 /* clear the structure */
1201 memset(last, '\0', sizeof(struct lastlog));
1202
1203 (void)line_stripname(last->ll_line, li->line,
1204 sizeof(last->ll_line));
1205 strlcpy(last->ll_host, li->hostname, sizeof(last->ll_host));
1206 last->ll_time = li->tv_sec;
andre61e67252000-06-04 17:07:49 +00001207}
andre2ff7b5d2000-06-03 14:57:40 +00001208
1209
1210#define LL_FILE 1
1211#define LL_DIR 2
1212#define LL_OTHER 3
1213
1214static int
andre61e67252000-06-04 17:07:49 +00001215lastlog_filetype(char *filename)
1216{
andre2ff7b5d2000-06-03 14:57:40 +00001217 struct stat st;
1218
1219 if ( stat(LASTLOG_FILE, &st) != 0) {
1220 log("lastlog_perform_login: Couldn't stat %s: %s",
1221 LASTLOG_FILE, strerror(errno));
1222 return 0;
1223 }
andre2ff7b5d2000-06-03 14:57:40 +00001224 if (S_ISDIR(st.st_mode))
1225 return LL_DIR;
1226 else if (S_ISREG(st.st_mode))
1227 return LL_FILE;
1228 else
1229 return LL_OTHER;
andre61e67252000-06-04 17:07:49 +00001230}
andre2ff7b5d2000-06-03 14:57:40 +00001231
1232
1233/* open the file (using filemode) and seek to the login entry */
1234static int
andre61e67252000-06-04 17:07:49 +00001235lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1236{
andre2ff7b5d2000-06-03 14:57:40 +00001237 off_t offset;
1238 int type;
1239 char lastlog_file[1024];
1240
1241 type = lastlog_filetype(LASTLOG_FILE);
1242 switch (type) {
1243 case LL_FILE:
1244 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1245 break;
1246 case LL_DIR:
1247 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1248 LASTLOG_FILE, li->username);
1249 break;
1250 default:
1251 log("lastlog_openseek: %.100s is not a file or directory!",
1252 LASTLOG_FILE);
1253 return 0;
1254 } /* switch */
1255
1256 *fd = open(lastlog_file, filemode);
1257 if ( *fd < 0) {
1258 log("lastlog_openseek: Couldn't open %s: %s",
1259 lastlog_file, strerror(errno));
1260 return 0;
1261 }
andre2ff7b5d2000-06-03 14:57:40 +00001262 /* find this uid's offset in the lastlog file */
1263 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
1264
1265 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1266 log("lastlog_openseek: %s->lseek(): %s",
1267 lastlog_file, strerror(errno));
1268 return 0;
1269 }
1270 return 1;
andre61e67252000-06-04 17:07:49 +00001271}
andre2ff7b5d2000-06-03 14:57:40 +00001272
1273static int
andre61e67252000-06-04 17:07:49 +00001274lastlog_perform_login(struct logininfo *li)
1275{
andre2ff7b5d2000-06-03 14:57:40 +00001276 struct lastlog last;
1277 int fd;
1278
1279 /* create our struct lastlog */
1280 lastlog_construct(li, &last);
1281
1282 /* write the entry */
1283 if (lastlog_openseek(li, &fd, O_RDWR)) {
1284 if ( write(fd, &last, sizeof(struct lastlog))
1285 != sizeof(struct lastlog) ) {
1286 log("lastlog_write_filemode: Error writing to %s: %s",
1287 LASTLOG_FILE, strerror(errno));
1288 return 0;
1289 }
1290 return 1;
1291 } else
1292 return 0;
andre61e67252000-06-04 17:07:49 +00001293}
andre2ff7b5d2000-06-03 14:57:40 +00001294
1295
1296int
andre61e67252000-06-04 17:07:49 +00001297lastlog_write_entry(struct logininfo *li)
1298{
andre2ff7b5d2000-06-03 14:57:40 +00001299 switch(li->type) {
1300 case LTYPE_LOGIN:
1301 return lastlog_perform_login(li);
1302 default:
1303 log("lastlog_write_entry: Invalid type field");
1304 return 0;
1305 }
andre61e67252000-06-04 17:07:49 +00001306}
andre2ff7b5d2000-06-03 14:57:40 +00001307
1308
1309static void
andre61e67252000-06-04 17:07:49 +00001310lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1311{
andre2ff7b5d2000-06-03 14:57:40 +00001312 line_fullname(li->line, last->ll_line, sizeof(li->line));
1313 strlcpy(li->hostname, last->ll_host, sizeof(li->hostname));
1314 li->tv_sec = last->ll_time;
andre61e67252000-06-04 17:07:49 +00001315}
andre2ff7b5d2000-06-03 14:57:40 +00001316
1317
1318int
andre61e67252000-06-04 17:07:49 +00001319lastlog_get_entry(struct logininfo *li)
1320{
andre2ff7b5d2000-06-03 14:57:40 +00001321 struct lastlog last;
1322 int fd;
1323
1324 if (lastlog_openseek(li, &fd, O_RDONLY)) {
1325 if ( read(fd, &last, sizeof(struct lastlog))
1326 != sizeof(struct lastlog) ) {
1327 log("lastlog_write_filemode: Error reading from %s: %s",
1328 LASTLOG_FILE, strerror(errno));
1329 return 0;
1330 } else {
1331 lastlog_populate_entry(li, &last);
1332 return 1;
1333 }
andre2ff7b5d2000-06-03 14:57:40 +00001334 } else
1335 return 0;
andre61e67252000-06-04 17:07:49 +00001336}
andre2ff7b5d2000-06-03 14:57:40 +00001337
1338
1339#endif
1340/* USE_LASTLOG */